3
0
mirror of https://github.com/triqs/dft_tools synced 2024-12-26 14:23:38 +01:00

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).
This commit is contained in:
Olivier Parcollet 2013-09-29 19:59:46 +02:00 committed by Michel Ferrero
parent 437c6e3a70
commit 59288e597f

View File

@ -46,15 +46,17 @@ namespace triqs { namespace clef {
template<typename T> struct force_copy_in_expr<T const> : force_copy_in_expr<T>{}; template<typename T> struct force_copy_in_expr<T const> : force_copy_in_expr<T>{};
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<T&> : std::conditional<force_copy_in_expr<T>::value, T ,std::reference_wrapper<T>>{}; template< class T > struct expr_storage_t<T&> : std::conditional<force_copy_in_expr<T>::value, typename std::remove_const<T>::type ,std::reference_wrapper<T>>{};
template< class T > struct expr_storage_t<T&&> {typedef T type;}; template< class T > struct expr_storage_t<T&&> {typedef T type;};
template< class T > struct expr_storage_t<const T&&> {typedef T type;};
template< class T > struct expr_storage_t<const T> {typedef T type;};
/* --------------------------------------------------------------------------------------------------- /* ---------------------------------------------------------------------------------------------------
* Placeholder and corresponding traits * Placeholder and corresponding traits
* --------------------------------------------------------------------------------------------------- */ * --------------------------------------------------------------------------------------------------- */
template<int i, typename T> class pair; // forward template<int i, typename T> class pair; // forward
// a placeholder is an empty struct, labelled by an int. // a placeholder is an empty struct, labelled by an int.
template<int N> struct placeholder { template<int N> struct placeholder {
static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]"); static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]");
static constexpr int index = N; static constexpr int index = N;
@ -90,11 +92,11 @@ namespace triqs { namespace clef {
std::integral_constant<bool, is_any_lazy<T>::value || is_any_lazy<Args...>::value> {}; std::integral_constant<bool, is_any_lazy<T>::value || is_any_lazy<Args...>::value> {};
template<typename T> template<typename T>
constexpr bool ClefExpression() { return is_any_lazy<T>::value;} constexpr bool ClefExpression() { return is_any_lazy<T>::value;}
template<typename T> struct is_clef_expression : is_any_lazy<T>{}; template<typename T> struct is_clef_expression : is_any_lazy<T>{};
/* --------------------------------------------------------------------------------------------------- /* ---------------------------------------------------------------------------------------------------
* Node of the expression tree * Node of the expression tree
* --------------------------------------------------------------------------------------------------- */ * --------------------------------------------------------------------------------------------------- */
template<typename Tag, typename... T> struct expr { template<typename Tag, typename... T> struct expr {
@ -136,7 +138,7 @@ namespace triqs { namespace clef {
template<typename Tag> struct operation; template<typename Tag> struct operation;
// a little function to clean the reference_wrapper // a little function to clean the reference_wrapper
template<typename U> U & _cl(U & x) { return x;} template<typename U> U _cl(U && x) { return std::forward<U>(x);}
template<typename U> U & _cl(std::reference_wrapper<U> x) { return x.get();} template<typename U> U & _cl(std::reference_wrapper<U> x) { return x.get();}
/// Terminal /// Terminal
@ -156,7 +158,7 @@ namespace triqs { namespace clef {
#define TRIQS_CLEF_OPERATION(TAG,OP)\ #define TRIQS_CLEF_OPERATION(TAG,OP)\
namespace tags { struct TAG : binary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\ namespace tags { struct TAG : binary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\
template<> struct operation<tags::TAG> {\ template<> struct operation<tags::TAG> {\
template<typename L, typename R> auto operator()(L const & l, R const & r) const DECL_AND_RETURN ( _cl(l) OP _cl(r));\ template<typename L, typename R> auto operator()(L && l, R && r) const DECL_AND_RETURN ( _cl(std::forward<L>(l)) OP _cl(std::forward<R>(r)));\
};\ };\
template<typename L, typename R>\ template<typename L, typename R>\
typename std::enable_if<is_any_lazy<L,R>::value, expr<tags::TAG,typename expr_storage_t<L>::type,typename expr_storage_t<R>::type> >::type \ typename std::enable_if<is_any_lazy<L,R>::value, expr<tags::TAG,typename expr_storage_t<L>::type,typename expr_storage_t<R>::type> >::type \
@ -189,7 +191,9 @@ namespace triqs { namespace clef {
/// the only ternary node : expression if /// the only ternary node : expression if
template<> struct operation<tags::if_else> { template<> struct operation<tags::if_else> {
template<typename C, typename A, typename B> 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<typename C, typename A, typename B> A operator()(C const & c, A const & a, B const & b) const {return _cl(c) ? _cl(a): _cl(b);}
//template<typename C, typename A, typename B> 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) // operator is : if_else( Condition, A, B)
template<typename C, typename A, typename B> template<typename C, typename A, typename B>
@ -199,79 +203,76 @@ namespace triqs { namespace clef {
/* --------------------------------------------------------------------------------------------------- /* ---------------------------------------------------------------------------------------------------
* Evaluation of the expression tree. * Evaluation of the expression tree.
* --------------------------------------------------------------------------------------------------- */ * --------------------------------------------------------------------------------------------------- */
template<typename ... T> struct _or;
template<typename T0, typename ... T> struct _or<T0,T...> : std::integral_constant<bool,T0::value || _or<T...>::value>{};
template<> struct _or<> : std::false_type{};
template<typename Tag, bool IsLazy, typename... Args> struct operation2; // Generic case : do nothing (for the leaf of the tree including placeholder)
template<typename Tag, typename... Args> struct operation2<Tag, true, Args...> {
typedef expr<Tag,typename remove_cv_ref<Args>::type ...> rtype;
rtype operator()(Args const & ... args) const {return rtype {Tag(), args...};}
};
template<typename Tag, typename... Args> struct operation2<Tag, false, Args...> {
typedef typename std::remove_reference<typename std::result_of<operation<Tag>(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<Tag>()(args...); }
};
// Generic case : do nothing (for the leaf of the tree except placeholder)
template<typename T, typename ... Pairs> struct evaluator{ template<typename T, typename ... Pairs> struct evaluator{
typedef T rtype; typedef is_any_lazy<T> is_lazy;
rtype operator()(T const & k, Pairs const &... pairs) {return k;} T operator()(T const & k, Pairs const &... pairs) { return k;}
}; };
// placeholder // placeholder
template<int N, int i, typename T, typename... Pairs> struct evaluator< placeholder<N>, pair<i,T>, Pairs... > { template<int N, int i, typename T, typename... Pairs> struct evaluator< placeholder<N>, pair<i,T>, Pairs... > {
typedef evaluator< placeholder<N>, Pairs...> eval_t; typedef evaluator< placeholder<N>, Pairs...> eval_t;
typedef typename eval_t::rtype rtype; typedef typename eval_t::is_lazy is_lazy;
rtype operator()(placeholder<N>, pair<i,T> const &, Pairs const& ... pairs) { return eval_t()(placeholder<N>(), pairs...);} auto operator()(placeholder<N>, pair<i,T> const &, Pairs const& ... pairs) DECL_AND_RETURN( eval_t()(placeholder<N>(), pairs...));
}; };
template<int N, typename T, typename... Pairs> struct evaluator< placeholder<N>, pair<N,T>, Pairs... > { template<int N, typename T, typename... Pairs> struct evaluator< placeholder<N>, pair<N,T>, Pairs... > {
typedef T const & rtype; typedef std::false_type is_lazy;
//typedef typename pair<N,T>::value_type const & rtype; T operator()(placeholder<N>, pair<N,T> const & p, Pairs const& ...) { return p.rhs;}
rtype operator()(placeholder<N>, pair<N,T> const & p, Pairs const& ...) { return p.rhs;} };
template<typename Tag, bool IsLazy> struct operation2;
template<typename Tag> struct operation2<Tag, true> {
template<typename... Args>
expr<Tag,typename remove_cv_ref<Args>::type ...> operator()(Args && ... args) const {
return {Tag(), std::forward<Args>(args)...};
}
};
template<typename Tag> struct operation2<Tag, false> {
template<typename... Args>
auto operator()(Args && ... args) const DECL_AND_RETURN( operation<Tag>()(std::forward<Args>(args)...));
void operator() (...) const {}
}; };
// general expr node // general expr node
template<typename Tag, typename... Childs, typename... Pairs> struct evaluator<expr<Tag, Childs...>, Pairs...> { template<int arity, typename Expr, typename... Pairs> struct evaluator_node_gal;
typedef operation2<Tag, is_any_lazy<typename evaluator<Childs, Pairs...>::rtype... >::value, typename evaluator<Childs, Pairs...>::rtype... > OPTYPE;
typedef typename OPTYPE::rtype rtype;
// first done manually for clearer error messages ... template<typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<1, expr<Tag, Childs...>, Pairs...> {
template< int arity = sizeof...(Childs)> typedef _or<typename evaluator<Childs, Pairs...>::is_lazy... > is_lazy;
typename std::enable_if< arity==1, rtype>::type typedef operation2<Tag, is_lazy::value > OPTYPE;
operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const auto operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const
{ return OPTYPE()(eval(std::get<0>(ex.childs),pairs...) );} DECL_AND_RETURN (OPTYPE()(eval(std::get<0>(ex.childs),pairs...)));
};
template< int arity = sizeof...(Childs)> template<typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<2, expr<Tag, Childs...>, Pairs...> {
typename std::enable_if< arity==2, rtype>::type typedef _or<typename evaluator<Childs, Pairs...>::is_lazy... > is_lazy;
operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const typedef operation2<Tag, is_lazy::value > OPTYPE;
{ return OPTYPE()(eval(std::get<0>(ex.childs),pairs...),eval(std::get<1>(ex.childs),pairs...) );} auto operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const
DECL_AND_RETURN (OPTYPE()(eval(std::get<0>(ex.childs),pairs...),eval(std::get<1>(ex.childs),pairs...)));
};
#define AUX(z,p,unused) eval(std::get<p>(ex.childs),pairs...) #define AUX(z,p,unused) eval(std::get<p>(ex.childs),pairs...)
#define IMPL(z, NN, unused) \ #define IMPL(z, NN, unused) \
template< int arity = sizeof...(Childs)>\ template<typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<NN, expr<Tag, Childs...>, Pairs...> {\
typename std::enable_if< arity==NN, rtype>::type\ typedef _or<typename evaluator<Childs, Pairs...>::is_lazy... > is_lazy;\
operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const\ typedef operation2<Tag, is_lazy::value > OPTYPE;\
{ return OPTYPE()(BOOST_PP_ENUM(NN,AUX,nil));} auto operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const\
BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil); 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 AUX
#undef IMPL #undef IMPL
};
#ifdef TRIQS_CLEF_EVAL_SHORT_CIRCUIT template<typename Tag, typename... Childs, typename... Pairs>
// A short circuit if intersection of ph and is 0, no need to evaluate the whole tree...... struct evaluator<expr<Tag, Childs...>, Pairs...> : evaluator_node_gal<sizeof...(Childs), expr<Tag, Childs...>, Pairs...>{};
// Seems useless, && the second eval is not correct if hte expression is a terminal.
template<typename T, typename... Pairs>
typename std::enable_if< (ph_set<T>::value & ph_set<Pairs...>::value) !=0, typename evaluator<T,Pairs...>::rtype > ::type
eval (T const & ex, Pairs const &... pairs) { return evaluator<T, Pairs...>()(ex, pairs...); }
template<typename T, typename... Pairs>
typename std::enable_if< (ph_set<T>::value & ph_set<Pairs...>::value) ==0, T const &> ::type
eval (T const & ex, Pairs const &... pairs) { return ex;}
#else
// The general eval function for expressions // The general eval function for expressions
template<typename T, typename... Pairs> template<typename T, typename... Pairs>
typename evaluator<T,Pairs...>::rtype auto eval (T const & ex, Pairs const &... pairs) DECL_AND_RETURN( evaluator<T, Pairs...>()(ex, pairs...));
eval (T const & ex, Pairs const &... pairs) { return evaluator<T, Pairs...>()(ex, pairs...); }
#endif
/* --------------------------------------------------------------------------------------------------- /* ---------------------------------------------------------------------------------------------------
* make_function : transform an expression to a function * make_function : transform an expression to a function
@ -284,17 +285,15 @@ namespace triqs { namespace clef {
// gcc 4.6 crashes (!!!) on the first variant // gcc 4.6 crashes (!!!) on the first variant
#ifndef TRIQS_COMPILER_OBSOLETE_GCC #ifndef TRIQS_COMPILER_OBSOLETE_GCC
template<typename... Args> template<typename... Args>
typename evaluator<Expr,pair<Is,Args>...>::rtype auto operator()(Args &&... args) const
operator()(Args &&... args) const DECL_AND_RETURN( evaluator<Expr,pair<Is,Args>...>() ( ex, pair<Is,Args>{std::forward<Args>(args)}...));
{ return evaluator<Expr,pair<Is,Args>...>() ( ex, pair<Is,Args>{std::forward<Args>(args)}...); }
#else #else
template<typename... Args> struct __eval { template<typename... Args> struct __eval {
typedef evaluator<Expr,pair<Is,Args>...> eval_t; typedef evaluator<Expr,pair<Is,Args>...> eval_t;
typedef typename eval_t::rtype rtype; auto operator()(Expr const &ex , Args &&... args) const DECL_AND_RETURN( return eval_t() ( ex, pair<Is,Args>{std::forward<Args>(args)}...));
rtype operator()(Expr const &ex , Args &&... args) const { return eval_t() ( ex, pair<Is,Args>{std::forward<Args>(args)}...); }
}; };
template<typename... Args> template<typename... Args>
typename __eval<Args...>::rtype operator()(Args &&... args) const { return __eval<Args...>() ( ex, std::forward<Args>(args)...); } auto operator()(Args &&... args) const DECL_AND_RETURN(return __eval<Args...>() ( ex, std::forward<Args>(args)...));
#endif #endif
}; };
@ -307,12 +306,6 @@ namespace triqs { namespace clef {
template< typename Expr, int... Is> struct is_any_lazy<make_fun_impl<Expr,Is...> > : std::integral_constant<bool,ph_set<make_fun_impl<Expr,Is...>>::value !=0>{}; template< typename Expr, int... Is> struct is_any_lazy<make_fun_impl<Expr,Is...> > : std::integral_constant<bool,ph_set<make_fun_impl<Expr,Is...>>::value !=0>{};
template< typename Expr, int... Is> struct force_copy_in_expr<make_fun_impl<Expr,Is...> > : std::true_type{}; template< typename Expr, int... Is> struct force_copy_in_expr<make_fun_impl<Expr,Is...> > : std::true_type{};
template< typename Expr, int... Is,typename... Pairs> struct evaluator<make_fun_impl<Expr,Is...>, Pairs...> {
typedef evaluator<Expr,Pairs...> e_t;
typedef make_fun_impl<typename e_t::rtype, Is...> rtype;
rtype operator()(make_fun_impl<Expr,Is...> const & f, Pairs const & ... pairs) const { return rtype( e_t()(f.ex, pairs...));}
};
template< typename Expr, typename ... Phs> template< typename Expr, typename ... Phs>
make_fun_impl<typename remove_cv_ref <Expr>::type,Phs::index...> make_fun_impl<typename remove_cv_ref <Expr>::type,Phs::index...>
make_function(Expr && ex, Phs...) { return {ex}; } make_function(Expr && ex, Phs...) { return {ex}; }
@ -323,11 +316,17 @@ namespace triqs { namespace clef {
}; };
} }
template< typename Expr, int... Is,typename... Pairs> struct evaluator<make_fun_impl<Expr,Is...>, Pairs...> {
typedef evaluator<Expr,Pairs...> e_t;
typedef std::integral_constant<bool, ph_set< make_fun_impl<Expr,Is...> >::value != ph_set<Pairs...>::value> is_lazy;
auto operator()(make_fun_impl<Expr,Is...> const & f, Pairs const & ... pairs) const DECL_AND_RETURN( make_function( e_t()(f.ex, pairs...),placeholder<Is>()...));
};
template<int ... N> struct ph_list {}; template<int ... N> struct ph_list {};
template<int ... N> ph_list<N...> var( placeholder<N> ...) { return {};} template<int ... N> ph_list<N...> var( placeholder<N> ...) { return {};}
template<typename Expr, int ... N> template<typename Expr, int ... N>
auto operator >> (ph_list<N...>, Expr const & ex) DECL_AND_RETURN( make_function(ex, placeholder<N>()...)); auto operator >> (ph_list<N...>, Expr const & ex) DECL_AND_RETURN( make_function(ex, placeholder<N>()...));
/* -------------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------------
* make_function * make_function
@ -400,15 +399,15 @@ namespace triqs { namespace clef {
void operator<<(expr<tags::subscript, F, placeholder<Is>...> const & ex, RHS && rhs) { void operator<<(expr<tags::subscript, F, placeholder<Is>...> const & ex, RHS && rhs) {
triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...)); triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
} }
template<typename F, typename RHS, int... Is> template<typename F, typename RHS, int... Is>
void operator<<(expr<tags::subscript, F, placeholder<Is>...> && ex, RHS && rhs) { void operator<<(expr<tags::subscript, F, placeholder<Is>...> && ex, RHS && rhs) {
triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...)); triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
} }
template<typename F, typename RHS, typename... T> template<typename F, typename RHS, typename... T>
void operator<<(expr<tags::subscript, F, T...> && ex, RHS && rhs) = delete; void operator<<(expr<tags::subscript, F, T...> && ex, RHS && rhs) = delete;
template<typename F, typename RHS, typename... T> template<typename F, typename RHS, typename... T>
void operator<<(expr<tags::subscript, F, T...> const & ex, RHS && rhs) = delete; void operator<<(expr<tags::subscript, F, T...> const & ex, RHS && rhs) = delete;
/* -------------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------------
@ -433,7 +432,7 @@ namespace triqs { namespace clef {
namespace _result_of { namespace _result_of {
template< typename Obj, typename... Args > struct make_expr_call : template< typename Obj, typename... Args > struct make_expr_call :
std::enable_if< is_any_lazy<Args...>::value, expr<tags::function,typename expr_storage_t<Obj>::type, typename expr_storage_t<Args>::type ...> > { std::enable_if< is_any_lazy<Args...>::value, expr<tags::function,typename expr_storage_t<Obj>::type, typename expr_storage_t<Args>::type ...> > {
static_assert (((arity<Obj>::value==-1) || (arity<Obj>::value == sizeof...(Args))), "Object called with a wrong number of arguments"); static_assert (((arity<Obj>::value==-1) || (arity<Obj>::value == sizeof...(Args))), "Object called with a wrong number of arguments");
}; };
} }
template< typename Obj, typename... Args > 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>(args)...)); auto operator()( Args&&... args ) const DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));
#else #else
template< typename... Args> template< typename... Args>
typename _result_of::make_expr_call<function const & ,Args...>::type typename _result_of::make_expr_call<function const & ,Args...>::type
operator()( Args&&... args ) const { return make_expr_call (*this,args...);} operator()( Args&&... args ) const { return make_expr_call (*this,args...);}
#endif #endif
@ -504,7 +503,7 @@ namespace triqs { namespace clef {
#ifndef TRIQS_COMPILER_OBSOLETE_GCC #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 { \ struct __clef_lazy_method_impl_##name { \
TY * _x;\ TY * _x;\
template<typename... A> auto operator()(A&&... a) const DECL_AND_RETURN (_x->name(std::forward<A>(a)...));\ template<typename... A> auto operator()(A&&... a) const DECL_AND_RETURN (_x->name(std::forward<A>(a)...));\