mirror of
https://github.com/triqs/dft_tools
synced 2024-12-27 06:43:40 +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:
parent
437c6e3a70
commit
59288e597f
@ -46,8 +46,10 @@ 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
|
||||||
@ -94,7 +96,7 @@ namespace triqs { namespace clef {
|
|||||||
|
|
||||||
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\
|
||||||
|
DECL_AND_RETURN ( OPTYPE()(BOOST_PP_ENUM(NN,AUX,nil)));\
|
||||||
|
};
|
||||||
BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, 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,6 +316,12 @@ 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 {};}
|
||||||
|
|
||||||
@ -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)...));\
|
||||||
|
Loading…
Reference in New Issue
Block a user