/******************************************************************************* * * 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 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(x0,f(x1,f(....)) 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<>)>{}; #ifdef TRIQS_COMPILER_IS_C11_COMPLIANT template using filter_t = typename filter_t_tr::type; #endif /** * 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<>)>{}; #ifdef TRIQS_COMPILER_IS_C11_COMPLIANT template using filter_out_t = typename filter_out_t_tr::type; #endif /** * 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 auto operator() (TupleIn const & t, TupleOut && out, R const & r) const DECL_AND_RETURN( replace_impl ()( t, push_back(std::forward(out),r),r)); }; // when pos == first I template struct replace_impl { template auto operator() (TupleIn const & t, TupleOut && out, R const & r) const DECL_AND_RETURN( replace_impl ()( t, push_back(std::forward(out),std::get(t)), r)); }; template struct replace_impl { template TupleOut operator() (TupleIn const & t, TupleOut && out, R const & r) const {return out;} }; template auto replace(Tu const & tu, R const &r) DECL_AND_RETURN ( replace_impl<0,std::tuple_size::value-1, I...>()(tu, std::make_tuple(),r)); /* * print a tuple */ template struct __s {}; template void print_tuple_impl (std::ostream& os, T const& t, std::integral_constant ) {} template void print_tuple_impl (std::ostream& os, T const& t, std::integral_constant ) { os << std::get(t); if (rpos>0) os << ','; print_tuple_impl(os, t, std::integral_constant()); } }} namespace std { template std::ostream & operator << (std::ostream & os, std::tuple const & t) { os << "("; constexpr int L = sizeof...(T); triqs::tuple::print_tuple_impl(os,t,std::integral_constant()); return os << ")"; } } #endif