/******************************************************************************* * * TRIQS: a Toolbox for Research in Interacting Quantum Systems * * Copyright (C) 2012-2014 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 . * ******************************************************************************/ #pragma once #include #include "./c14.hpp" #include #include // adding to the std lib the reversed lazy tuple... // overloading & specializing only the functions needed here. namespace std { // Reverse 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_DECL get(_triqs_reversed_tuple const & t) RETURN(std::get>::value-1-pos>(t._x)); template AUTO_DECL get(_triqs_reversed_tuple & t) RETURN(std::get>::value-1-pos>(t._x)); template AUTO_DECL get(_triqs_reversed_tuple && t) RETURN(std::get>::value-1-pos>(move(t)._x)); template class tuple_size<_triqs_reversed_tuple> : public tuple_size> {}; // Zipped tuple: template struct _triqs_zipped_tuple { std::tuple _tu; template _triqs_zipped_tuple(U &&... u) : _tu(std::forward(u)...) {} template auto _get(std::c14::index_sequence) RETURN(std::tie(std::get(std::get(_tu))...)); template auto _get(std::c14::index_sequence) const RETURN(std::tie(std::get(std::get(_tu))...)); }; template AUTO_DECL get(_triqs_zipped_tuple const &tu) RETURN(tu.template _get(std14::make_index_sequence())); template struct tuple_size<_triqs_zipped_tuple> : public std::tuple_size> {}; template _triqs_zipped_tuple zip(T &&... x) { return {std::forward(x)...}; } } namespace triqs { namespace tuple { /// _get_seq() : from a tuple T, return the index sequence of the tuple length template std14::make_index_sequence>::value> _get_seq() { return {}; } /// _get_seq_len : constexpr : return the length of the tuple template constexpr int _get_seq_len() { return std::tuple_size>::value; } /// basic tools template struct _int {}; template struct all_indices : _int... {}; // --- impl complement ----- template struct complement_sequence_impl { static complement_sequence_impl get(_int) {} static complement_sequence_impl get(...) {} using type = typename decltype(get(hole_seq()))::type; }; template struct complement_sequence_impl<-1, hole_seq, Is...> { using type = std14::index_sequence; }; /// An index sequence of elements of [0,N-1] which are NOT Is template using complement_sequence = typename complement_sequence_impl>::type; /** * apply(f, t) * f : a callable object * t a tuple * Returns : f(t0, t1 ...) * Cf : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3915.pdf * for the idea of using the sequence, which is used several times below. */ template AUTO_DECL apply_impl(F &&f, T &&t, std14::index_sequence) RETURN(f(std::get(std::forward(t))...)); template AUTO_DECL apply(F &&f, T &&t) RETURN(apply_impl(std::forward(f), std::forward(t), _get_seq())); /** * apply_construct(t) * C : a class * t a tuple * Returns : C{t0, t1, ....} */ template AUTO_DECL apply_construct_impl(T &&t, std14::index_sequence) RETURN(C{std::get(std::forward(t))...}); template AUTO_DECL apply_construct(T &&t) RETURN(apply_construct_impl(std::forward(t), _get_seq())); /** * called_on_tuple(f) * f : a callable object * Wrapping a function to make it callable from a tuple * called_on_tuple(f)( std::tie(x0,x1,x2)) is equivalent to f(x0,x1,x2) */ template struct _called_on_tuple { F _f; template AUTO_DECL operator()(Tu &&tu) RETURN(apply(_f, std::forward(tu))); }; template _called_on_tuple called_on_tuple(F &&f) { return {std::forward(f)}; } // Implementation tools // _for_each_impl (f, x0, x1, ..., xn) calls f(x0); f(x1); ... f(xn); IN THIS ORDER template void _for_each_impl(F &&f) {} template void _for_each_impl(F &&f, T0 &&x0, T &&... x) { f(std::forward(x0)); _for_each_impl(f, std::forward(x)...); } // _for_each_apply_impl (f, t0, t1, ..., tn) calls apply(f,x0); apply(f,t1); ... apply(f,tn); template void _for_each_apply_impl(F &&f) {} template void _for_each_apply_impl(F &&f, T0 &&t0, T &&... t) { apply(f, std::forward(t0)); _for_each_apply_impl(f, std::forward(t)...); } /** * for_each(t, f) * t: a tuple * f: a callable object * calls f on all tuple elements in the order of the tuple: f(x) for all x in t */ template void for_each_impl(F &&f, T &&t, std14::index_sequence) { _for_each_impl(f, std::get(t)...); } template void for_each(T &&t, F &&f) { for_each_impl(f, std::forward(t), _get_seq()); } /* for_each_enumerate(t, f) * t: a tuple * f: a callable object * calls f on all tuple elements: * Python equivalent : * for n,x in enumrate(t): f(n,x) */ template void _for_each_enum_impl(F &&f, T &&t, std14::index_sequence) { _for_each_apply_impl(f, std::tuple(t))>(Is, std::get(t))...); // not make_tuple here, we keep the ref given by the get } template void for_each_enumerate(T &&t, F &&f) { _for_each_enum_impl(f, std::forward(t), _get_seq()); } /** * for_each_zip(f, t1,t2) * f : a callable object * t1,t2 : two tuples * calls f on all tuple elements: f(x1,x2) for x1 in t1 for x2 in t2 */ template void _for_each_zip_impl(std14::index_sequence, F &&f, T0 &&t0, T1 &&t1) { _for_each_impl(called_on_tuple(std::forward(f)), std::tie(std::get(t0), std::get(t1))...); } template void for_each_zip(F &&f, T0 &&t0, T1 &&t1) { _for_each_zip_impl(_get_seq(), std::forward(f), std::forward(t0), std::forward(t1)); } /** * for_each_zip(f, t1,t2,t3) * f : a callable object * t1,t2,t3 : three tuples * calls f on all tuple elements: f(x1,x2,x3) for x1 in t1 for x2 in t2 for x3 in t3 */ template void _for_each_zip_impl(std14::index_sequence, F &&f, T0 &&t0, T1 &&t1, T2 &&t2) { _for_each_impl(called_on_tuple(std::forward(f)), std::tie(std::get(t0), std::get(t1), std::get(t2))...); } template void for_each_zip(F &&f, T0 &&t0, T1 &&t1, T2 &&t2) { _for_each_zip_impl(_get_seq(), std::forward(f), std::forward(t0), std::forward(t1), std::forward(t2)); } /** * map(f, t) * f : a callable object * t tuple * Returns : [f(i) for i in t] */ template AUTO_DECL _map_impl(F &&f, T &&t, std14::index_sequence) RETURN(std::make_tuple(std::forward(f)(std::get(t))...)); template AUTO_DECL map(F &&f, T &&t) RETURN(_map_impl(std::forward(f), std::forward(t), _get_seq())); /** * map_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 auto _map_impl(F &&f, T0 &&t0, T1 &&t1, std14::index_sequence) RETURN(std::make_tuple(std::forward(f)(std::get(t0), std::get(t1))...)); template auto map_on_zip(F &&f, T0 &&t0, T1 &&t1) RETURN(_map_impl(std::forward(f), std::forward(t0), std::forward(t1), _get_seq())); template auto map_on_zip_v2(F &&f, T0 &&t0, T1 &&t1) RETURN(map(called_on_tuple(f), zip(t0,t1))); /** * map_on_zip(f,t0,t1,t2) * f : a callable object * t0, t1, t2 two tuples of the same size * Returns : [f(i,j,k) for i,j,k in zip(t0,t1,t2)] */ template auto _map_impl(F &&f, T0 &&t0, T1 &&t1, T2 &&t2, std14::index_sequence) RETURN(std::make_tuple(std::forward(f)(std::get(t0), std::get(t1), std::get(t2))...)); template auto map_on_zip(F &&f, T0 &&t0, T1 &&t1, T2 &&t2) RETURN(_map_impl(std::forward(f), std::forward(t0), std::forward(t1), std::forward(t2), _get_seq())); /** * fold(f, t1, r_init) * f : a callable object : f(x,r) -> r' * t a tuple * Returns : f(xN,f(x_N-1,...f(x0,r_init)) on the tuple */ #ifndef TRIQS_C11 template decltype(auto) fold_impl(_int, F &&f, T &&t, R &&r) { return fold_impl(_int(), std::forward(f), std::forward(t), f(std::get<_get_seq_len() - 1 - pos>(t), std::forward(r))); } template R fold_impl(_int<-1>, F &&f, T &&t, R &&r) { return std::forward(r); } template decltype(auto) fold(F &&f, T &&t, R &&r) { return fold_impl(_int<_get_seq_len() - 1>(), std::forward(f), std::forward(t), std::forward(r)); } #else // old implementation, not modified for C++11 template struct fold_impl { template auto operator()(F &&f, T &&t, R &&r)DECL_AND_RETURN(fold_impl()(std::forward(f), std::forward(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), std::forward(t), std::forward(r))); #endif /** * fold(f, r_init, t1, t2) * 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...). */ #ifndef TRIQS_C11 template decltype(auto) fold_impl(_int, F &&f, T0 &&t0, T1 &&t1, R &&r) { constexpr int n = _get_seq_len() - 1 - pos; return fold_impl(_int(), std::forward(f), std::forward(t0), std::forward(t1), f(std::get(t0), std::get(t1), std::forward(r))); } template R fold_impl(_int<-1>, F &&f, T0 &&t0, T1 &&t1, R &&r) { return std::forward(r); } template decltype(auto) fold(F &&f, T0 &&t0, T1 &&t1, R &&r) { return fold_impl(_int<_get_seq_len() - 1>(), std::forward(f), std::forward(t0), std::forward(t1), std::forward(r)); } #else // old implementation, not modified for C++11 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(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))); #endif /** * replace(t,r) * Given a tuple t, and integers, returns the tuple where the elements at initial position I are replaced by r */ template R _get_rpl(T &&x, R &&r, _int) { return std::forward(r); } template T _get_rpl(T &&x, R &&r, ...) { return std::forward(x); } template auto _replace_impl(Tu &&tu, R &&r, AllIndices _, std14::index_sequence) RETURN(std::make_tuple(_get_rpl(std::get(tu), r, _)...)); template auto replace(Tu &&tu, R &&r) RETURN(_replace_impl(tu, r, all_indices(), _get_seq())); /** * filter(t) : * Given a tuple t, and integers, returns the tuple where the elements at initial position I are kept. */ template using filter_t = std::tuple>::type...>; template filter_t filter(Tu &&tu) { return filter_t(std::get(std::forward(tu))...); } template filter_t filter(Tu &&tu, std14::index_sequence) { return filter_t(std::get(std::forward(tu))...); } /** * filter_out(t) : * Given a tuple t, and integers, returns the tuple where the elements at initial position I are dropped. */ template AUTO_DECL filter_out(Tu &&tu) RETURN(filter(tu, complement_sequence>::value - 1, I...>())); template using filter_out_t = std14::decay_t(std::declval()))>; /** * 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) 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) RETURN(std::tuple_cat(std::make_tuple(std::forward(x)), std::forward(t))); /// To be rewritten .... /** * 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)); /* * print a tuple */ inline void _triqs_print_tuple_impl(std::ostream &os) {} template void _triqs_print_tuple_impl(std::ostream &os, T0 const &x0, T const &... x) { os << x0; if (sizeof...(T) > 0) os << ','; _triqs_print_tuple_impl(os, x...); } template void _triqs_print_tuple(std::ostream &os, std::tuple const &t, std14::index_sequence) { _triqs_print_tuple_impl(os, std::get(t)...); } } } namespace std { template std::ostream &operator<<(std::ostream &os, std::tuple const &t) { os << "("; triqs::tuple::_triqs_print_tuple(os, t, std14::make_index_sequence()); return os << ")"; } // do not move this up.... namespace c14 { // a little helper class to wait for the correction that tuple construct is NOT explicit template class tuple : public std::tuple { public: template tuple(Args2 &&... args2) : std::tuple(std::forward(args2)...) {} }; } // minimal hack to get the metaprogramming work with this tuple too.... template auto get(c14::tuple const &t) DECL_AND_RETURN(std::get(static_cast>(t))); template class tuple_size> : public tuple_size> {}; }