/*******************************************************************************
*
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
*
* Copyright (C) 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 .
*
******************************************************************************/
#ifndef TRIQS_UTILITY_TUPLE_TOOLS_H
#define TRIQS_UTILITY_TUPLE_TOOLS_H
#include
#include
#include
// adding to the std lib the reversed lazy tuple...
// overloading & specializing only the functions needed here.
namespace std {
template struct _triqs_reversed_tuple {TU _x;};
template _triqs_reversed_tuple> reverse(std::tuple && x) { return {move(x)};}
template _triqs_reversed_tuple&> reverse(std::tuple & x) { return {x};}
template _triqs_reversed_tupleconst &> reverse(std::tuple const & x) { return {x};}
template auto get(_triqs_reversed_tuple const & t)
DECL_AND_RETURN(std::get::type>::type>::value-1-pos>(t._x));
template auto get(_triqs_reversed_tuple & t)
DECL_AND_RETURN(std::get::type>::type>::value-1-pos>(t._x));
template auto get(_triqs_reversed_tuple && t)
DECL_AND_RETURN(std::get::type>::type>::value-1-pos>(move(t)._x));
template struct tuple_size<_triqs_reversed_tuple> : tuple_size::type>::type>{};
}
namespace triqs { namespace tuple {
/**
* t : a tuple
* x : anything
* push_back (t,x) -> returns new tuple with x append at the end
*/
template
auto push_back(T && t, X &&x) DECL_AND_RETURN ( std::tuple_cat(std::forward(t),std::make_tuple(std::forward(x))));
/**
* t : a tuple
* x : anything
* push_front (t,x) -> returns new tuple with x append at the first position
*/
template
auto push_front(T && t, X &&x) DECL_AND_RETURN ( std::tuple_cat(std::make_tuple(std::forward(x)),std::forward(t)));
/**
* apply(f, t)
* f : a callable object
* t a tuple
* Returns : f(t[0], t[1], ...)
* Equivalent to f(*t) in python ....
*/
template struct apply_impl {
template
auto operator()(F && f, T const & t, Args && ... args)
DECL_AND_RETURN( apply_impl()(std::forward(f),t, std::get(t), std::forward(args)...));
};
template<> struct apply_impl<-1> {
template
auto operator()(F && f, T const & t, Args && ... args) DECL_AND_RETURN( std::forward(f)(std::forward(args)...));
};
template
auto apply (F && f, T const & t) DECL_AND_RETURN( apply_impl::value-1>()(std::forward(f),t));
//template
//ReturnType apply( ReturnType(*f)(Args...), T const & t) { return apply([f](Args const & ... args) { return (*f)(args...);} ,t);}
/**
* apply_construct(t)
* F : a class
* t a tuple
* Returns : F { t[0], t[1]}
*/
template struct apply_construct_impl {
template
auto operator()(T const & t, Args && ... args)
DECL_AND_RETURN( apply_construct_impl()(t, std::get(t), std::forward(args)...));
};
template struct apply_construct_impl<-1,F,T> {
template
auto operator()(T const & t, Args && ... args) DECL_AND_RETURN( F{std::forward(args)...});
};
template
auto apply_construct (T const & t) DECL_AND_RETURN( apply_construct_impl::value-1,F,T>()(t));
/**
* for_each(f, t)
* f: a callable object
* t: a tuple
* calls f on all tuple elements: f(x) for all x in t
*/
template struct for_each_impl {
template
void operator()(T const & t, F && f) {
f(std::get::value-1-pos>(t));
for_each_impl()(t, f);
}
};
template<>
struct for_each_impl<0> {
template
void operator() (T const & t, F && f) { f(std::get::value-1>(t)); }
};
template
void for_each(T const & t, F && f) {
for_each_impl::value-1>()(t, f);
}
/* for_each_enumerate(f, t)
* f: a callable object
* t: a tuple
* calls f on all tuple elements: f(x,n) for all x in t
*/
template struct for_each_enumerate_impl {
template
void operator()(T const & t, F && f) {
f(std::get::value-1-pos>(t),std::tuple_size::value-1-pos);
for_each_impl()(t, f);
}
};
template<>
struct for_each_enumerate_impl<0> {
template
void operator() (T const & t, F && f) { f(std::get::value-1>(t), std::tuple_size::value-1); }
};
template
void for_each_enumerate(T const & t, F && f) {
for_each_enumerate_impl::value-1>()(t, f);
}
/**
* apply_on_tuple(f, t1,t2)
* f : a callable object
* t1, t2 two tuples of the same size
* Returns : [f(i,j) for i,j in zip(t1,t2)]
*/
template struct apply_on_tuple_impl {
template
auto operator()(F && f, T1 && t1, Args && ... args)
DECL_AND_RETURN( apply_on_tuple_impl()(std::forward(f),std::forward(t1), f(std::get(t1)), std::forward(args)...));
};
template<> struct apply_on_tuple_impl<-1> {
template
auto operator()(F && f, T1 && t1, Args && ... args) DECL_AND_RETURN( std::make_tuple(std::forward(args)...));
};
template
auto apply_on_tuple (F && f,T1 && t1) DECL_AND_RETURN( apply_on_tuple_impl::type>::value-1>()(std::forward(f),std::forward(t1)));
/**
* apply_on_zip(f, t1,t2)
* f : a callable object
* t1, t2 two tuples of the same size
* Returns : [f(i,j) for i,j in zip(t1,t2)]
*/
template struct apply_on_zip_impl {
template
auto operator()(F && f, T1 && t1, T2 && t2, Args && ... args)
DECL_AND_RETURN( apply_on_zip_impl()(std::forward(f),std::forward(t1), std::forward(t2), f(std::get(t1),std::get(t2)), std::forward(args)...));
};
template<> struct apply_on_zip_impl<-1> {
template
auto operator()(F && f, T1 && t1, T2 && t2, Args && ... args) DECL_AND_RETURN( std::make_tuple(std::forward(args)...));
};
template
auto apply_on_zip (F && f,T1 && t1, T2 && t2) DECL_AND_RETURN( apply_on_zip_impl::type>::type>::value-1>()(std::forward(f),std::forward(t1),std::forward(t2)));
/**
* apply_on_zip(f, t1,t2,t3)
* f : a callable object
* t1, t2 two tuples of the same size
* Returns : [f(i,j) for i,j in zip(t1,t2)]
*/
template struct apply_on_zip3_impl {
template
auto operator()(F && f, T1 && t1, T2 && t2, T3 && t3, Args && ... args)
DECL_AND_RETURN( apply_on_zip3_impl()(std::forward(f),std::forward(t1), std::forward(t2), std::forward(t3),
f(std::get(t1),std::get(t2),std::get(t3)), std::forward(args)...));
};
template<> struct apply_on_zip3_impl<-1> {
template
auto operator()(F && f, T1 && t1, T2 && t2, T3 && t3, Args && ... args) DECL_AND_RETURN( std::make_tuple(std::forward(args)...));
};
template
auto apply_on_zip (F && f,T1 && t1, T2 && t2, T3 && t3) DECL_AND_RETURN( apply_on_zip3_impl::type>::type>::value-1>()(std::forward(f),std::forward(t1),std::forward(t2),std::forward(t3)));
/**
* call_on_zip(f, t1,t2,t3)
* f : a callable object
* t1, t2, t3 three tuples of the same size
* Returns : void
* Effect : calls f(i,j,k) for all(i,j,k) in zip(t1,t2,t3)]
*/
template struct call_on_zip3_impl {
template
void operator()(F && f, T1 && t1, T2 && t2, T3 && t3) {
f(std::get(std::forward(t1)),std::get(std::forward(t2)),std::get(std::forward(t3)));
call_on_zip3_impl()(std::forward(f),std::forward(t1), std::forward(t2), std::forward(t3));
}
};
template<> struct call_on_zip3_impl<-1> {
template void operator()(F && f, T1 && t1, T2 && t2, T3 && t3){}
};
template
void call_on_zip (F && f,T1 && t1, T2 && t2, T3 && t3) {
call_on_zip3_impl::type>::value-1>()(std::forward(f),std::forward(t1),std::forward(t2),std::forward(t3));
}
/**
* fold(f, t1, init)
* f : a callable object
* t a tuple
* Returns : f(xN,f(x_N-1,...f(x0,r)) on the tuple
*/
template struct fold_impl {
template
auto operator()(F && f, T & t, R && r )
DECL_AND_RETURN( fold_impl()(std::forward(f),t, f(std::get(t), std::forward(r))));
};
template struct fold_impl {
template R operator()(F && f, T & t, R && r) {return std::forward(r);}
};
template
auto fold (F && f,T & t, R && r) DECL_AND_RETURN( fold_impl::value,std::tuple_size::value-1,T>()(std::forward(f),t,std::forward(r)));
template
auto fold (F && f,T const & t, R && r) DECL_AND_RETURN( fold_impl::value,std::tuple_size::value-1,T const>()(std::forward(f),t,std::forward(r)));
/**
* fold_on_zip(f, t1, t2, init)
* f : a callable object
* t1, t2 two tuples of the same size
* Returns : f(x0,y0,f(x1,y1,,f(....)) for t1 = (x0,x1 ...) and t2 = (y0,y1...).
*/
template struct fold_on_zip_impl {
template
auto operator()(F && f, T1 const & t1, T2 const & t2, R && r )
DECL_AND_RETURN( fold_on_zip_impl()(std::forward(f),t1,t2, f(std::get(t1), std::get(t2), std::forward(r))));
};
template struct fold_on_zip_impl<-1,T1,T2> {
template R operator()(F && f, T1 const & t1, T2 const & t2, R && r) {return std::forward(r);}
};
template
auto fold_on_zip (F && f,T1 const & t1, T2 const & t2, R && r) DECL_AND_RETURN( fold_on_zip_impl::value-1,T1,T2>()(std::forward(f),t1,t2,std::forward(r)));
/**
* filter(t) :
* Given a tuple t, and integers, returns the tuple where the elements at initial position I are dropped.
*/
// pos = position in the tuple, c : counter tuplesize-1 ->0, I : position to filter
template struct filter_impl;
// default case where pos != the first I : increase pos
template struct filter_impl : filter_impl {};
// when pos == first I
template struct filter_impl {
template auto operator() (TupleIn const & t, TupleOut && out) const
DECL_AND_RETURN( filter_impl() ( t, push_back(std::forward(out),std::get(t))));
};
template struct filter_impl {
template TupleOut operator() (TupleIn const & t, TupleOut && out) const {return out;}
};
template
auto filter(Tu const & tu) DECL_AND_RETURN ( filter_impl<0,std::tuple_size::value-1, I...>()(tu, std::make_tuple()));
template struct filter_t_tr : std::result_of< filter_impl<0,std::tuple_size::value-1, I...>( Tu, std::tuple<>)>{};
template using filter_t = typename filter_t_tr::type;
/**
* filter_out(t) :
* Given a tuple t, and integers, returns the tuple where the elements at initial position I are dropped.
*/
// pos = position in the tuple, c : counter tuplesize-1 ->0, I : position to filter
template struct filter_out_impl;
// default case where pos != the first I : increase pos
template struct filter_out_impl : filter_out_impl {};
// when pos == first I
template struct filter_out_impl {
template auto operator() (TupleIn const & t, TupleOut && out) const
DECL_AND_RETURN( filter_out_impl ()( t, push_back(std::forward(out),std::get(t))));
};
template struct filter_out_impl {
template TupleOut operator() (TupleIn const & t, TupleOut && out) const {return out;}
};
template
auto filter_out(Tu const & tu) DECL_AND_RETURN ( filter_out_impl<0,std::tuple_size::value-1, I...>()(tu, std::make_tuple()));
template struct filter_out_t_tr : std::result_of< filter_out_impl<0,std::tuple_size::value-1, I...>( Tu, std::tuple<>)>{};
template using filter_out_t = typename filter_out_t_tr::type;
/**
* inverse_filter(t,x)
* Given a tuple t, and integers, returns the tuple R of size L such that filter(R) == t
* and the missing position are filled with object x.
* Precondition (static_assert : sizeof...(I)==size of t)
* and max (I) < L
*/
// pos = position in the tuple, c : counter tuplesize-1 ->0, I : position to filter
template struct inverse_filter_impl;
// default case where pos != the first I
template struct inverse_filter_impl {
template auto operator() (TupleIn const & t, TupleOut && out, X const & x) const
DECL_AND_RETURN( inverse_filter_impl ()( t, push_back(std::forward(out),std::get(t)),x));
};
// when pos == first I
template struct inverse_filter_impl {
template auto operator() (TupleIn const & t, TupleOut && out, X const & x) const
DECL_AND_RETURN( inverse_filter_impl ()( t, push_back(std::forward(out),x), x));
};
template struct inverse_filter_impl {
template TupleOut operator() (TupleIn const &, TupleOut && out, X const &) const {return out;}
};
// put out for clearer error message
template< typename Tu, typename X, int L, int ...I> struct inverse_filter_r_type {
static_assert(sizeof...(I) == std::tuple_size::value, "inverse filter : the # of int must be equal to the tuple size !!");
typedef inverse_filter_impl<0,0,L-1, I...> type;
};
template
auto inverse_filter(Tu const & tu, X const &x) DECL_AND_RETURN ( typename inverse_filter_r_type::type ()(tu, std::make_tuple(),x));
/**
* inverse_filter_out(t,x)
* Given a tuple t, and integers, returns the tuple R such that filter_out(R) == t
* and the missing position are filled with object x.
*/
// pos = position in the tuple, c : counter tuplesize-1 ->0, I : position to filter
template struct inverse_filter_out_impl;
// default case where pos != the first I
template struct inverse_filter_out_impl {
template auto operator() (TupleIn const & t, TupleOut && out, X const & x) const
DECL_AND_RETURN( inverse_filter_out_impl ()( t, push_back(std::forward(out),std::get(t)),x));
};
// when pos == first I
template struct inverse_filter_out_impl {
template auto operator() (TupleIn const & t, TupleOut && out, X const & x) const
DECL_AND_RETURN( inverse_filter_out_impl ()( t, push_back(std::forward(out),x), x));
};
template struct inverse_filter_out_impl {
template TupleOut operator() (TupleIn const &, TupleOut && out, X const &) const {return out;}
};
template
auto inverse_filter_out(Tu const & tu, X const &x) DECL_AND_RETURN ( inverse_filter_out_impl<0,0,std::tuple_size::value+sizeof...(I)-1, I...>()(tu, std::make_tuple(),x));
/**
* replace(t,r)
* Given a tuple t, and integers, returns the tuple where the elements at initial position I are replaced by r
*/
// pos = position in the tuple, c : counter tuplesize-1 ->0, I : position to filter
template struct replace_impl;
// default case where pos != the first I : increase pos
template struct replace_impl {
template