mirror of
https://github.com/triqs/dft_tools
synced 2024-10-31 19:23:45 +01:00
59288e597f
- 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).
550 lines
29 KiB
C++
550 lines
29 KiB
C++
/*******************************************************************************
|
|
*
|
|
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
|
|
*
|
|
* Copyright (C) 2012-2013 by O. Parcollet
|
|
*
|
|
* TRIQS is free software: you can redistribute it and/or modify it under the
|
|
* terms of the GNU General Public License as published by the Free Software
|
|
* Foundation, either version 3 of the License, or (at your option) any later
|
|
* version.
|
|
*
|
|
* TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* TRIQS. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
******************************************************************************/
|
|
#ifndef TRIQS_CLEF_CORE_H
|
|
#define TRIQS_CLEF_CORE_H
|
|
#include <triqs/utility/first_include.hpp>
|
|
#include <triqs/utility/macros.hpp>
|
|
#include <triqs/utility/compiler_details.hpp>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <complex>
|
|
#include <boost/preprocessor/stringize.hpp>
|
|
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
|
#include <boost/preprocessor/repetition/enum.hpp>
|
|
#include <boost/preprocessor/arithmetic/inc.hpp>
|
|
|
|
#define TRIQS_CLEF_MAXNARGS 8
|
|
|
|
namespace triqs { namespace clef {
|
|
typedef unsigned long long ull_t;
|
|
namespace tags { struct function_class{}; struct function{}; struct subscript{}; struct terminal{}; struct if_else{}; struct unary_op{}; struct binary_op{}; }
|
|
|
|
// Compute the type to put in the expression tree.
|
|
// If T is a lvalue reference, pack it into a reference_wrapper, unless force_copy_in_expr<T>::value == true
|
|
// If T is an rvalue reference, we store it as the type (using move semantics).
|
|
template<typename T> struct force_copy_in_expr : std::false_type{};
|
|
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<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<const T&&> {typedef T type;};
|
|
template< class T > struct expr_storage_t<const T> {typedef T type;};
|
|
|
|
/* ---------------------------------------------------------------------------------------------------
|
|
* Placeholder and corresponding traits
|
|
* --------------------------------------------------------------------------------------------------- */
|
|
template<int i, typename T> class pair; // forward
|
|
|
|
// a placeholder is an empty struct, labelled by an int.
|
|
template<int N> struct placeholder {
|
|
static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]");
|
|
static constexpr int index = N;
|
|
template <typename RHS> pair<N,RHS> operator = (RHS && rhs) { return {std::forward<RHS>(rhs)};}
|
|
};
|
|
|
|
// placeholder will always be copied (they are empty anyway).
|
|
template< int N > struct force_copy_in_expr<placeholder<N>> : std::true_type{};
|
|
|
|
// represent a couple (placeholder, value).
|
|
template<int N, typename U> struct pair {
|
|
U rhs;
|
|
static constexpr int p = N;
|
|
typedef typename remove_cv_ref <U>::type value_type;
|
|
};
|
|
|
|
// ph_set is a trait that given a pack of type, returns the set of placeholders they contain
|
|
// it returns a int in binary coding : bit N in the int is 1 iif at least one T is lazy and contains placeholder<N>
|
|
template<typename... T> struct ph_set;
|
|
template<typename T0, typename... T> struct ph_set<T0,T...>{static constexpr ull_t value= ph_set<T0>::value| ph_set<T...>::value;};
|
|
template<typename T> struct ph_set<T> {static constexpr ull_t value= 0;};
|
|
template<int N> struct ph_set<placeholder<N>> {static constexpr ull_t value= 1ull<<N;};
|
|
template<int i, typename T> struct ph_set<pair<i,T> > : ph_set<placeholder<i>>{};
|
|
|
|
// in_any_lazy : trait to detect if any of Args is a lazy expression
|
|
template<typename... Args> struct is_any_lazy : std::false_type {};
|
|
template<int N> struct is_any_lazy <placeholder <N> > : std::true_type {};
|
|
template <typename T> struct is_any_lazy< T > : std::false_type {};
|
|
template <typename T> struct is_any_lazy< T&& > : is_any_lazy<T> {};
|
|
template <typename T> struct is_any_lazy< T& > : is_any_lazy<T> {};
|
|
template <typename T> struct is_any_lazy< T const > : is_any_lazy<T> {};
|
|
template<typename T, typename... Args> struct is_any_lazy<T, Args...> :
|
|
std::integral_constant<bool, is_any_lazy<T>::value || is_any_lazy<Args...>::value> {};
|
|
|
|
template<typename T>
|
|
constexpr bool ClefExpression() { return is_any_lazy<T>::value;}
|
|
|
|
template<typename T> struct is_clef_expression : is_any_lazy<T>{};
|
|
|
|
/* ---------------------------------------------------------------------------------------------------
|
|
* Node of the expression tree
|
|
* --------------------------------------------------------------------------------------------------- */
|
|
template<typename Tag, typename... T> struct expr {
|
|
// T can be U, U & (a reference or a value).
|
|
typedef std::tuple<T...> childs_t;
|
|
childs_t childs;
|
|
expr(expr const & x) = default;
|
|
expr(expr && x) noexcept : childs(std::move(x.childs)) {}
|
|
// a constructor with the Tag make it unambiguous with other constructors...
|
|
template<typename... Args> expr(Tag, Args&&...args) : childs(std::forward<Args>(args)...) {}
|
|
// [] returns a new lazy expression, with one more layer
|
|
template<typename Args>
|
|
expr<tags::subscript, expr, typename expr_storage_t<Args>::type > operator[](Args && args) const
|
|
{ return {tags::subscript(), *this,std::forward<Args>(args)};}
|
|
// () also ...
|
|
template< typename... Args >
|
|
expr<tags::function, expr, typename expr_storage_t<Args>::type...> operator()(Args && ... args) const
|
|
{ return {tags::function(), *this,std::forward<Args>(args)...};}
|
|
// assignement is in general deleted
|
|
expr & operator= (expr const &) = delete; // no ordinary assignment
|
|
expr & operator= (expr &&) = default; // move assign ok
|
|
// however, this is ok in the case f(i,j) = expr, where f is a clef::function
|
|
template<typename RHS, typename CH = childs_t>
|
|
ENABLE_IF(std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>)
|
|
operator= (RHS const & rhs) { *this << rhs;}
|
|
template<typename RHS, typename CH = childs_t>
|
|
DISABLE_IF(std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>)
|
|
operator= (RHS const & rhs) = delete;
|
|
};
|
|
// set some traits
|
|
template<typename Tag, typename... T> struct ph_set< expr<Tag,T... > > : ph_set<T...> {};
|
|
template<typename Tag, typename... T> struct is_any_lazy< expr<Tag,T... > >: std::true_type {};
|
|
// if we want that subexpression are copied ?
|
|
template<typename Tag, typename... T> struct force_copy_in_expr< expr<Tag,T... > > : std::true_type{};
|
|
|
|
/* ---------------------------------------------------------------------------------------------------
|
|
* The basic operations put in a template....
|
|
* --------------------------------------------------------------------------------------------------- */
|
|
template<typename Tag> struct operation;
|
|
|
|
// a little function to clean the reference_wrapper
|
|
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();}
|
|
|
|
/// Terminal
|
|
template<> struct operation<tags::terminal> { template<typename L> L operator()(L&& l) const { return std::forward<L>(l);} };
|
|
|
|
/// Function call
|
|
template<> struct operation<tags::function> {
|
|
template<typename F, typename... Args> auto operator()(F const & f, Args const & ... args) const DECL_AND_RETURN(_cl(f)(_cl(args)...));
|
|
};
|
|
|
|
/// [ ] Call
|
|
template<> struct operation<tags::subscript> {
|
|
template<typename F, typename Args> auto operator()(F const & f, Args const & args) const DECL_AND_RETURN(_cl(f)[_cl(args)]);
|
|
};
|
|
|
|
// all binary operators....
|
|
#define TRIQS_CLEF_OPERATION(TAG,OP)\
|
|
namespace tags { struct TAG : binary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\
|
|
template<> struct operation<tags::TAG> {\
|
|
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>\
|
|
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 \
|
|
operator OP (L && l, R && r) { return {tags::TAG(),std::forward<L>(l),std::forward<R>(r)};}\
|
|
|
|
TRIQS_CLEF_OPERATION(plus, +);
|
|
TRIQS_CLEF_OPERATION(minus, -);
|
|
TRIQS_CLEF_OPERATION(multiplies, *);
|
|
TRIQS_CLEF_OPERATION(divides, /);
|
|
TRIQS_CLEF_OPERATION(greater, >);
|
|
TRIQS_CLEF_OPERATION(less, <);
|
|
TRIQS_CLEF_OPERATION(leq, <=);
|
|
TRIQS_CLEF_OPERATION(geq, >=);
|
|
TRIQS_CLEF_OPERATION(eq, ==);
|
|
#undef TRIQS_CLEF_OPERATION
|
|
|
|
// all unary operators....
|
|
#define TRIQS_CLEF_OPERATION(TAG,OP)\
|
|
namespace tags { struct TAG : unary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\
|
|
template<> struct operation<tags::TAG> {\
|
|
template<typename L> auto operator()(L const & l) const DECL_AND_RETURN (OP _cl(l));\
|
|
};\
|
|
template<typename L>\
|
|
typename std::enable_if<is_any_lazy<L>::value, expr<tags::TAG,typename expr_storage_t<L>::type> >::type \
|
|
operator OP (L && l) { return {tags::TAG(),std::forward<L>(l)};}\
|
|
|
|
TRIQS_CLEF_OPERATION(negate, -);
|
|
TRIQS_CLEF_OPERATION(loginot, !);
|
|
#undef TRIQS_CLEF_OPERATION
|
|
|
|
/// the only ternary node : expression if
|
|
template<> struct operation<tags::if_else> {
|
|
// 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)
|
|
template<typename C, typename A, typename B>
|
|
expr<tags::if_else,typename expr_storage_t<C>::type,typename expr_storage_t<A>::type,typename expr_storage_t<B>::type>
|
|
if_else(C && c, A && a, B && b) { return {tags::if_else(),std::forward<C>(c),std::forward<A>(a),std::forward<B>(b)};}
|
|
|
|
/* ---------------------------------------------------------------------------------------------------
|
|
* 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{};
|
|
|
|
// Generic case : do nothing (for the leaf of the tree including placeholder)
|
|
template<typename T, typename ... Pairs> struct evaluator{
|
|
typedef is_any_lazy<T> is_lazy;
|
|
T operator()(T const & k, Pairs const &... pairs) { return k;}
|
|
};
|
|
|
|
// placeholder
|
|
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 typename eval_t::is_lazy is_lazy;
|
|
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... > {
|
|
typedef std::false_type is_lazy;
|
|
T 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
|
|
template<int arity, typename Expr, typename... Pairs> struct evaluator_node_gal;
|
|
|
|
template<typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<1, expr<Tag, Childs...>, Pairs...> {
|
|
typedef _or<typename evaluator<Childs, Pairs...>::is_lazy... > is_lazy;
|
|
typedef operation2<Tag, is_lazy::value > OPTYPE;
|
|
auto operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const
|
|
DECL_AND_RETURN (OPTYPE()(eval(std::get<0>(ex.childs),pairs...)));
|
|
};
|
|
|
|
template<typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<2, expr<Tag, Childs...>, Pairs...> {
|
|
typedef _or<typename evaluator<Childs, Pairs...>::is_lazy... > is_lazy;
|
|
typedef operation2<Tag, is_lazy::value > OPTYPE;
|
|
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 IMPL(z, NN, unused) \
|
|
template<typename Tag, typename... Childs, typename... Pairs> struct evaluator_node_gal<NN, expr<Tag, Childs...>, Pairs...> {\
|
|
typedef _or<typename evaluator<Childs, Pairs...>::is_lazy... > is_lazy;\
|
|
typedef operation2<Tag, is_lazy::value > OPTYPE;\
|
|
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);
|
|
#undef AUX
|
|
#undef IMPL
|
|
|
|
template<typename Tag, typename... Childs, typename... Pairs>
|
|
struct evaluator<expr<Tag, Childs...>, Pairs...> : evaluator_node_gal<sizeof...(Childs), expr<Tag, Childs...>, Pairs...>{};
|
|
|
|
// The general eval function for expressions
|
|
template<typename T, typename... Pairs>
|
|
auto eval (T const & ex, Pairs const &... pairs) DECL_AND_RETURN( evaluator<T, Pairs...>()(ex, pairs...));
|
|
|
|
/* ---------------------------------------------------------------------------------------------------
|
|
* make_function : transform an expression to a function
|
|
* --------------------------------------------------------------------------------------------------- */
|
|
|
|
template< typename Expr, int... Is> struct make_fun_impl {
|
|
Expr ex; // keep a copy of the expression
|
|
make_fun_impl(Expr const & ex_) : ex(ex_) {}
|
|
|
|
// gcc 4.6 crashes (!!!) on the first variant
|
|
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
|
|
template<typename... Args>
|
|
auto operator()(Args &&... args) const
|
|
DECL_AND_RETURN( evaluator<Expr,pair<Is,Args>...>() ( ex, pair<Is,Args>{std::forward<Args>(args)}...));
|
|
#else
|
|
template<typename... Args> struct __eval {
|
|
typedef evaluator<Expr,pair<Is,Args>...> eval_t;
|
|
auto operator()(Expr const &ex , Args &&... args) const DECL_AND_RETURN( return eval_t() ( ex, pair<Is,Args>{std::forward<Args>(args)}...));
|
|
};
|
|
template<typename... Args>
|
|
auto operator()(Args &&... args) const DECL_AND_RETURN(return __eval<Args...>() ( ex, std::forward<Args>(args)...));
|
|
#endif
|
|
};
|
|
|
|
// values of the ph, excluding the Is ...
|
|
template<ull_t x, int... Is> struct ph_filter;
|
|
template<ull_t x, int I0, int... Is> struct ph_filter<x,I0,Is...> { static constexpr ull_t value = ph_filter<x,Is...>::value & (~ (1ull<<I0));};
|
|
template<ull_t x> struct ph_filter<x> { static constexpr ull_t value = x; };
|
|
|
|
template< typename Expr, int... Is> struct ph_set<make_fun_impl<Expr,Is...> > { static constexpr ull_t value = ph_filter <ph_set<Expr>::value, Is...>::value;};
|
|
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, typename ... Phs>
|
|
make_fun_impl<typename remove_cv_ref <Expr>::type,Phs::index...>
|
|
make_function(Expr && ex, Phs...) { return {ex}; }
|
|
|
|
namespace result_of {
|
|
template< typename Expr, typename ... Phs> struct make_function {
|
|
typedef make_fun_impl<typename remove_cv_ref<Expr>::type,Phs::index...> type;
|
|
};
|
|
}
|
|
|
|
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> ph_list<N...> var( placeholder<N> ...) { return {};}
|
|
|
|
template<typename Expr, int ... N>
|
|
auto operator >> (ph_list<N...>, Expr const & ex) DECL_AND_RETURN( make_function(ex, placeholder<N>()...));
|
|
|
|
/* --------------------------------------------------------------------------------------------------
|
|
* make_function
|
|
* x_ >> expression is the same as make_function(expression,x)
|
|
* --------------------------------------------------------------------------------------------------- */
|
|
|
|
template <int N, typename Expr>
|
|
make_fun_impl<Expr,N > operator >> (placeholder<N> p, Expr&& ex) { return {ex}; }
|
|
|
|
/* ---------------------------------------------------------------------------------------------------
|
|
* Auto assign for ()
|
|
* --------------------------------------------------------------------------------------------------- */
|
|
|
|
// by default it is deleted = not implemented : every class has to define it...
|
|
template<typename T, typename F> void triqs_clef_auto_assign (T,F) = delete;
|
|
|
|
// remove the ref_wrapper, terminal ...
|
|
template<typename T, typename F> void triqs_clef_auto_assign (std::reference_wrapper<T> R ,F && f) { triqs_clef_auto_assign(R.get(),std::forward<F>(f));}
|
|
template<typename T, typename F> void triqs_clef_auto_assign (expr<tags::terminal,T> const & t,F && f) { triqs_clef_auto_assign(std::get<0>(t.childs),std::forward<F>(f));}
|
|
|
|
// auto assign of an expr ? (for chain calls) : just reuse the same operator
|
|
template<typename Tag, typename... Childs, typename RHS>
|
|
void triqs_clef_auto_assign (expr<Tag,Childs...> && ex, RHS const & rhs) { ex << rhs;}
|
|
|
|
template<typename Tag, typename... Childs, typename RHS>
|
|
void triqs_clef_auto_assign (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << rhs;}
|
|
|
|
// The case A(x_,y_) = RHS : we form the function (make_function) and call auto_assign (by ADL)
|
|
template<typename F, typename RHS, int... Is>
|
|
void operator<<(expr<tags::function, F, placeholder<Is>...> && ex, RHS && rhs) {
|
|
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
|
}
|
|
template<typename F, typename RHS, int... Is>
|
|
void operator<<(expr<tags::function, F, placeholder<Is>...> const & ex, RHS && rhs) {
|
|
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
|
}
|
|
template<typename F, typename RHS, int... Is>
|
|
void operator<<(expr<tags::function, F, placeholder<Is>...> & ex, RHS && rhs) {
|
|
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
|
}
|
|
|
|
// any other case e.g. f(x_+y_) = RHS etc .... which makes no sense : compiler will stop
|
|
template<typename F, typename RHS, typename... T>
|
|
void operator<<(expr<tags::function, F, T...> && ex, RHS && rhs) = delete;
|
|
template<typename F, typename RHS, typename... T>
|
|
void operator<<(expr<tags::function, F, T...> const & ex, RHS && rhs) = delete;
|
|
|
|
/* ---------------------------------------------------------------------------------------------------
|
|
* Auto assign for []
|
|
* --------------------------------------------------------------------------------------------------- */
|
|
|
|
// by default it is deleted = not implemented : every class has to define it...
|
|
template<typename T, typename F> void triqs_clef_auto_assign_subscript (T,F) = delete;
|
|
|
|
// remove the ref_wrapper, terminal ...
|
|
template<typename T, typename F> void triqs_clef_auto_assign_subscript (std::reference_wrapper<T> R ,F && f)
|
|
{ triqs_clef_auto_assign_subscript(R.get(),std::forward<F>(f));}
|
|
template<typename T, typename F> void triqs_clef_auto_assign_subscript (expr<tags::terminal,T> const & t,F && f)
|
|
{ triqs_clef_auto_assign_subscript(std::get<0>(t.childs),std::forward<F>(f));}
|
|
|
|
// auto assign of an expr ? (for chain calls) : just reuse the same operator
|
|
template<typename Tag, typename... Childs, typename RHS>
|
|
void triqs_clef_auto_assign_subscript (expr<Tag,Childs...> && ex, RHS const & rhs) { ex << rhs;}
|
|
|
|
template<typename Tag, typename... Childs, typename RHS>
|
|
void triqs_clef_auto_assign_subscript (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << rhs;}
|
|
|
|
// Same thing for the [ ]
|
|
template<typename F, typename RHS, int... Is>
|
|
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>()...));
|
|
}
|
|
template<typename F, typename RHS, int... Is>
|
|
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>()...));
|
|
}
|
|
|
|
template<typename F, typename RHS, typename... T>
|
|
void operator<<(expr<tags::subscript, F, T...> && ex, RHS && rhs) = delete;
|
|
|
|
template<typename F, typename RHS, typename... T>
|
|
void operator<<(expr<tags::subscript, F, T...> const & ex, RHS && rhs) = delete;
|
|
|
|
/* --------------------------------------------------------------------------------------------------
|
|
* Create a terminal node of an object. the from clone version force copying the object
|
|
* --------------------------------------------------------------------------------------------------- */
|
|
|
|
// make a node with the ref, unless it is an rvalue (which is moved).
|
|
template<typename T> expr<tags::terminal,typename expr_storage_t<T>::type >
|
|
make_expr(T && x){ return {tags::terminal(), std::forward<T>(x)};}
|
|
|
|
// make a node from a copy of the object
|
|
template<typename T> expr<tags::terminal,typename remove_cv_ref<T>::type >
|
|
make_expr_from_clone(T && x){ return {tags::terminal(), std::forward<T>(x)};}
|
|
|
|
/* --------------------------------------------------------------------------------------------------
|
|
* Create a call node of an object
|
|
* The object can be kept as a : a ref, a copy, a view
|
|
* --------------------------------------------------------------------------------------------------- */
|
|
|
|
template<typename T> struct arity { static constexpr int value =-1;};
|
|
|
|
namespace _result_of {
|
|
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 ...> > {
|
|
static_assert (((arity<Obj>::value==-1) || (arity<Obj>::value == sizeof...(Args))), "Object called with a wrong number of arguments");
|
|
};
|
|
}
|
|
template< typename Obj, typename... Args >
|
|
typename _result_of::make_expr_call<Obj,Args...>::type
|
|
make_expr_call(Obj&& obj, Args &&... args) { return {tags::function(),std::forward<Obj>(obj), std::forward<Args>(args)...};}
|
|
|
|
/* --------------------------------------------------------------------------------------------------
|
|
* Create a [] call (subscript) node of an object
|
|
* The object can be kept as a : a ref, a copy, a view
|
|
* --------------------------------------------------------------------------------------------------- */
|
|
|
|
namespace _result_of {
|
|
template< typename Obj, typename Arg> struct make_expr_subscript :
|
|
std::enable_if< is_any_lazy<Arg>::value, expr<tags::subscript,typename expr_storage_t<Obj>::type, typename expr_storage_t<Arg>::type> > {};
|
|
}
|
|
template< typename Obj, typename Arg>
|
|
typename _result_of::make_expr_subscript<Obj,Arg>::type
|
|
make_expr_subscript(Obj&& obj, Arg && arg) { return {tags::subscript(),std::forward<Obj>(obj), std::forward<Arg>(arg)};}
|
|
|
|
/* --------------------------------------------------------------------------------------------------
|
|
* function class : stores any expression polymorphically
|
|
* f(x_,y_ ) = an expression associates this expression dynamically to f, which
|
|
* can then be used as a std::function of the same signature...
|
|
* --------------------------------------------------------------------------------------------------- */
|
|
template<typename F> class function;
|
|
|
|
template<typename ReturnType, typename... T> class function<ReturnType(T...)> : tags::function_class {
|
|
typedef std::function<ReturnType(T...)> std_function_type;
|
|
mutable std::shared_ptr <void> _exp; // CLEAN THIS MUTABLE ?
|
|
mutable std::shared_ptr < std_function_type > _fnt_ptr;
|
|
public:
|
|
function():_fnt_ptr{std::make_shared<std_function_type> ()}{}
|
|
|
|
template<typename Expr, typename... X>
|
|
explicit function(Expr const & _e, X... x) : _exp(new Expr(_e)),_fnt_ptr(new std_function_type(make_function(_e, x...))){}
|
|
|
|
ReturnType operator()(T const &... t) const { return (*_fnt_ptr)(t...);}
|
|
|
|
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
|
|
template< typename... Args>
|
|
auto operator()( Args&&... args ) const DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));
|
|
#else
|
|
template< typename... Args>
|
|
typename _result_of::make_expr_call<function const & ,Args...>::type
|
|
operator()( Args&&... args ) const { return make_expr_call (*this,args...);}
|
|
#endif
|
|
|
|
template<typename RHS> friend void triqs_clef_auto_assign (function const & x, RHS rhs) {
|
|
* (x._fnt_ptr) = std_function_type (rhs);
|
|
x._exp = std::shared_ptr <void> (new typename std::remove_cv<decltype(rhs.ex)>::type (rhs.ex));
|
|
}
|
|
|
|
};
|
|
template<typename F> struct force_copy_in_expr <function<F>> : 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
|
|
* taking expressions (at least one argument has to be an expression)
|
|
* The lookup happens by ADL, so IT MUST BE USED IN THE triqs::lazy namespace
|
|
* --------------------------------------------------------------------------------------------------- */
|
|
#define TRIQS_CLEF_MAKE_FNT_LAZY(name)\
|
|
struct name##_lazy_impl { \
|
|
template<typename... A> auto operator()(A&&... a) const DECL_AND_RETURN (name(std::forward<A>(a)...));\
|
|
};\
|
|
template< typename... A> \
|
|
auto name( A&& ... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(),std::forward<A>(a)...));
|
|
|
|
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
|
|
|
|
#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY,name)\
|
|
struct __clef_lazy_method_impl_##name { \
|
|
TY * _x;\
|
|
template<typename... A> auto operator()(A&&... a) const DECL_AND_RETURN (_x->name(std::forward<A>(a)...));\
|
|
friend std::ostream & operator<<(std::ostream & out, __clef_lazy_method_impl_##name const & x) { return out<<BOOST_PP_STRINGIZE(TY)<<"."<<BOOST_PP_STRINGIZE(name);}\
|
|
};\
|
|
template< typename... A> \
|
|
auto name( A&& ... a) DECL_AND_RETURN (make_expr_call(__clef_lazy_method_impl_##name{this},std::forward<A>(a)...));
|
|
|
|
#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(...)\
|
|
template< typename... Args>\
|
|
auto operator()(Args&&... args ) const & DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));\
|
|
\
|
|
template< typename... Args>\
|
|
auto operator()(Args&&... args ) & DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));\
|
|
\
|
|
template< typename... Args>\
|
|
auto operator()(Args&&... args ) && DECL_AND_RETURN(make_expr_call (std::move(*this),std::forward<Args>(args)...));\
|
|
|
|
#else
|
|
|
|
#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY,name,RETURN_TYPE)\
|
|
struct __clef_lazy_method_impl_##name { \
|
|
TY * _x;\
|
|
template<typename... A> RETURN_TYPE operator()(A&&... a) const {return ((*_x).name(std::forward<A>(a)...));}\
|
|
friend std::ostream & operator<<(std::ostream & out, __clef_lazy_method_impl_##name const & x) { return out<<BOOST_PP_STRINGIZE(TY)<<"."<<BOOST_PP_STRINGIZE(name);}\
|
|
};\
|
|
template< typename... A> \
|
|
typename _result_of::make_expr_call<__clef_lazy_method_impl_##name, A...>::type\
|
|
name( A&& ... a) {return make_expr_call(__clef_lazy_method_impl_##name{this},std::forward<A>(a)...);}
|
|
|
|
#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(TY)\
|
|
template< typename... Args>\
|
|
typename triqs::clef::_result_of::make_expr_call<TY const &,Args...>::type\
|
|
operator()(Args&&... args ) const {return make_expr_call (*this,std::forward<Args>(args)...);}\
|
|
\
|
|
template< typename... Args>\
|
|
typename triqs::clef::_result_of::make_expr_call<TY &,Args...>::type\
|
|
operator()(Args&&... args ) {return make_expr_call (*this,std::forward<Args>(args)...);}
|
|
|
|
#endif
|
|
|
|
}} // namespace triqs::clef
|
|
#endif
|