3
0
mirror of https://github.com/triqs/dft_tools synced 2024-12-25 22:03:43 +01:00
dft_tools/triqs/utility/tuple_tools.hpp
Olivier Parcollet 36a60ce529 tuple tools : simplify
- simplify implementation of several functions.
- clean API, rename, etc...
- add more documentation
2014-06-21 21:11:33 +02:00

497 lines
21 KiB
C++

/*******************************************************************************
*
* 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 <http://www.gnu.org/licenses/>.
*
******************************************************************************/
#pragma once
#include<triqs/utility/macros.hpp>
#include "./c14.hpp"
#include <tuple>
#include <ostream>
// adding to the std lib the reversed lazy tuple...
// overloading & specializing only the functions needed here.
namespace std {
// Reverse
template<typename TU> struct _triqs_reversed_tuple {TU _x;};
template<typename ... T> _triqs_reversed_tuple<std::tuple<T...>> reverse(std::tuple<T...> && x) { return {move(x)};}
template<typename ... T> _triqs_reversed_tuple<std::tuple<T...>&> reverse(std::tuple<T...> & x) { return {x};}
template<typename ... T> _triqs_reversed_tuple<std::tuple<T...>const &> reverse(std::tuple<T...> const & x) { return {x};}
template<int pos, typename TU> AUTO_DECL get(_triqs_reversed_tuple<TU> const & t)
RETURN(std::get<std::tuple_size<std14::decay_t<TU>>::value-1-pos>(t._x));
template<int pos, typename TU> AUTO_DECL get(_triqs_reversed_tuple<TU> & t)
RETURN(std::get<std::tuple_size<std14::decay_t<TU>>::value-1-pos>(t._x));
template<int pos, typename TU> AUTO_DECL get(_triqs_reversed_tuple<TU> && t)
RETURN(std::get<std::tuple_size<std14::decay_t<TU>>::value-1-pos>(move(t)._x));
template <typename TU> class tuple_size<_triqs_reversed_tuple<TU>> : public tuple_size<std14::decay_t<TU>> {};
// Zipped tuple:
template <typename... T> struct _triqs_zipped_tuple {
std::tuple<T...> _tu;
template <typename... U> _triqs_zipped_tuple(U &&... u) : _tu(std::forward<U>(u)...) {}
template <size_t I, size_t... Is> auto _get(std::c14::index_sequence<Is...>) RETURN(std::tie(std::get<I>(std::get<Is>(_tu))...));
template <size_t I, size_t... Is> auto _get(std::c14::index_sequence<Is...>) const RETURN(std::tie(std::get<I>(std::get<Is>(_tu))...));
};
template <size_t I, typename... T>
AUTO_DECL get(_triqs_zipped_tuple<T...> const &tu) RETURN(tu.template _get<I>(std14::make_index_sequence<sizeof...(T)>()));
template <typename T0, typename... T> struct tuple_size<_triqs_zipped_tuple<T0, T...>> : public std::tuple_size<std14::decay_t<T0>> {};
template <typename... T> _triqs_zipped_tuple<T...> zip(T &&... x) {
return {std::forward<T>(x)...};
}
}
namespace triqs { namespace tuple {
/// _get_seq<T>() : from a tuple T, return the index sequence of the tuple length
template <typename T> std14::make_index_sequence<std::tuple_size<std14::decay_t<T>>::value> _get_seq() {
return {};
}
/// _get_seq_len<T> : constexpr : return the length of the tuple
template <typename Tu> constexpr int _get_seq_len() { return std::tuple_size<std14::decay_t<Tu>>::value; }
/// basic tools
template <int N> struct _int {};
template <int... Is> struct all_indices : _int<Is>... {};
// --- impl complement -----
template <int N, typename hole_seq, int... Is> struct complement_sequence_impl {
static complement_sequence_impl<N - 1, hole_seq, Is...> get(_int<N>) {}
static complement_sequence_impl<N - 1, hole_seq, N, Is...> get(...) {}
using type = typename decltype(get(hole_seq()))::type;
};
template <typename hole_seq, int... Is> struct complement_sequence_impl<-1, hole_seq, Is...> {
using type = std14::index_sequence<Is...>;
};
/// An index sequence of elements of [0,N-1] which are NOT Is
template <int N, int... Is> using complement_sequence = typename complement_sequence_impl<N, all_indices<Is...>>::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 <typename F, typename T, size_t... Is>
AUTO_DECL apply_impl(F &&f, T &&t, std14::index_sequence<Is...>) RETURN(f(std::get<Is>(std::forward<T>(t))...));
template <typename F, typename T>
AUTO_DECL apply(F &&f, T &&t) RETURN(apply_impl(std::forward<F>(f), std::forward<T>(t), _get_seq<T>()));
/**
* apply_construct<C>(t)
* C : a class
* t a tuple
* Returns : C{t0, t1, ....}
*/
template <typename C, typename T, size_t... Is>
AUTO_DECL apply_construct_impl(T &&t, std14::index_sequence<Is...>) RETURN(C{std::get<Is>(std::forward<T>(t))...});
template <typename C, typename T>
AUTO_DECL apply_construct(T &&t) RETURN(apply_construct_impl<C>(std::forward<T>(t), _get_seq<T>()));
/**
* 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 <typename F> struct _called_on_tuple {
F _f;
template <typename Tu> AUTO_DECL operator()(Tu &&tu) RETURN(apply(_f, std::forward<Tu>(tu)));
};
template <typename F> _called_on_tuple<F> called_on_tuple(F &&f) {
return {std::forward<F>(f)};
}
// Implementation tools
// _for_each_impl (f, x0, x1, ..., xn) calls f(x0); f(x1); ... f(xn); IN THIS ORDER
template <typename F> void _for_each_impl(F &&f) {}
template <typename F, typename T0, typename... T> void _for_each_impl(F &&f, T0 &&x0, T &&... x) {
f(std::forward<T0>(x0));
_for_each_impl(f, std::forward<T>(x)...);
}
// _for_each_apply_impl (f, t0, t1, ..., tn) calls apply(f,x0); apply(f,t1); ... apply(f,tn);
template <typename F> void _for_each_apply_impl(F &&f) {}
template <typename F, typename T0, typename... T> void _for_each_apply_impl(F &&f, T0 &&t0, T &&... t) {
apply(f, std::forward<T0>(t0));
_for_each_apply_impl(f, std::forward<T>(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 <typename F, typename T, size_t... Is> void for_each_impl(F &&f, T &&t, std14::index_sequence<Is...>) {
_for_each_impl(f, std::get<Is>(t)...);
}
template <typename T, typename F> void for_each(T &&t, F &&f) { for_each_impl(f, std::forward<T>(t), _get_seq<T>()); }
/* 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 <typename F, typename T, size_t... Is> void _for_each_enum_impl(F &&f, T &&t, std14::index_sequence<Is...>) {
_for_each_apply_impl(f, std::tuple<int, decltype(std::get<Is>(t))>(Is, std::get<Is>(t))...);
// not make_tuple here, we keep the ref given by the get
}
template <typename T, typename F> void for_each_enumerate(T &&t, F &&f) {
_for_each_enum_impl(f, std::forward<T>(t), _get_seq<T>());
}
/**
* 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 <typename F, typename T0, typename T1, size_t... Is>
void _for_each_zip_impl(std14::index_sequence<Is...>, F &&f, T0 &&t0, T1 &&t1) {
_for_each_impl(called_on_tuple(std::forward<F>(f)), std::tie(std::get<Is>(t0), std::get<Is>(t1))...);
}
template <typename F, typename T0, typename T1> void for_each_zip(F &&f, T0 &&t0, T1 &&t1) {
_for_each_zip_impl(_get_seq<T0>(), std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(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 <typename F, typename T0, typename T1, typename T2, size_t... Is>
void _for_each_zip_impl(std14::index_sequence<Is...>, F &&f, T0 &&t0, T1 &&t1, T2 &&t2) {
_for_each_impl(called_on_tuple(std::forward<F>(f)), std::tie(std::get<Is>(t0), std::get<Is>(t1), std::get<Is>(t2))...);
}
template <typename F, typename T0, typename T1, typename T2> void for_each_zip(F &&f, T0 &&t0, T1 &&t1, T2 &&t2) {
_for_each_zip_impl(_get_seq<T0>(), std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1), std::forward<T2>(t2));
}
/**
* map(f, t)
* f : a callable object
* t tuple
* Returns : [f(i) for i in t]
*/
template <typename F, typename T, size_t... Is>
AUTO_DECL _map_impl(F &&f, T &&t, std14::index_sequence<Is...>)
RETURN(std::make_tuple(std::forward<F>(f)(std::get<Is>(t))...));
template <typename T, typename F>
AUTO_DECL map(F &&f, T &&t) RETURN(_map_impl(std::forward<F>(f), std::forward<T>(t), _get_seq<T>()));
/**
* 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 <typename F, typename T0, typename T1, size_t... Is>
auto _map_impl(F &&f, T0 &&t0, T1 &&t1, std14::index_sequence<Is...>)
RETURN(std::make_tuple(std::forward<F>(f)(std::get<Is>(t0), std::get<Is>(t1))...));
template <typename T0, typename T1, typename F>
auto map_on_zip(F &&f, T0 &&t0, T1 &&t1)
RETURN(_map_impl(std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1), _get_seq<T0>()));
template <typename T0, typename T1, typename F>
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 <typename F, typename T0, typename T1, typename T2, size_t... Is>
auto _map_impl(F &&f, T0 &&t0, T1 &&t1, T2 &&t2, std14::index_sequence<Is...>)
RETURN(std::make_tuple(std::forward<F>(f)(std::get<Is>(t0), std::get<Is>(t1), std::get<Is>(t2))...));
template <typename T0, typename T1, typename T2, typename F>
auto map_on_zip(F &&f, T0 &&t0, T1 &&t1, T2 &&t2)
RETURN(_map_impl(std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1), std::forward<T2>(t2), _get_seq<T0>()));
/**
* 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 <int pos, typename F, typename T, typename R> decltype(auto) fold_impl(_int<pos>, F &&f, T &&t, R &&r) {
return fold_impl(_int<pos - 1>(), std::forward<F>(f), std::forward<T>(t),
f(std::get<_get_seq_len<T>() - 1 - pos>(t), std::forward<R>(r)));
}
template <typename F, typename T, typename R> R fold_impl(_int<-1>, F &&f, T &&t, R &&r) { return std::forward<R>(r); }
template <typename F, typename T, typename R> decltype(auto) fold(F &&f, T &&t, R &&r) {
return fold_impl(_int<_get_seq_len<T>() - 1>(), std::forward<F>(f), std::forward<T>(t), std::forward<R>(r));
}
#else
// old implementation, not modified for C++11
template <int N, int pos, typename T> struct fold_impl {
template <typename F, typename R>
auto operator()(F &&f, T &&t,
R &&r)DECL_AND_RETURN(fold_impl<N, pos - 1, T>()(std::forward<F>(f), std::forward<T>(t),
f(std::get<N - 1 - pos>(t), std::forward<R>(r))));
};
template <int N, typename T> struct fold_impl<N, -1, T> {
template <typename F, typename R> R operator()(F &&f, T &&t, R &&r) { return std::forward<R>(r); }
};
template <typename F, typename T, typename R>
auto fold(F &&f, T &&t, R &&r)
DECL_AND_RETURN(fold_impl<std::tuple_size<std::c14::decay_t<T>>::value, std::tuple_size<std::c14::decay_t<T>>::value - 1,
T>()(std::forward<F>(f), std::forward<T>(t), std::forward<R>(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 <int pos, typename F, typename T0, typename T1, typename R>
decltype(auto) fold_impl(_int<pos>, F &&f, T0 &&t0, T1 &&t1, R &&r) {
constexpr int n = _get_seq_len<T0>() - 1 - pos;
return fold_impl(_int<pos - 1>(), std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1),
f(std::get<n>(t0), std::get<n>(t1), std::forward<R>(r)));
}
template <typename F, typename T0, typename T1, typename R> R fold_impl(_int<-1>, F &&f, T0 &&t0, T1 &&t1, R &&r) {
return std::forward<R>(r);
}
template <typename F, typename T0, typename T1, typename R> decltype(auto) fold(F &&f, T0 &&t0, T1 &&t1, R &&r) {
return fold_impl(_int<_get_seq_len<T0>() - 1>(), std::forward<F>(f), std::forward<T0>(t0), std::forward<T1>(t1),
std::forward<R>(r));
}
#else
// old implementation, not modified for C++11
template <int pos, typename T1, typename T2> struct fold_on_zip_impl {
template <typename F, typename R>
auto operator()(F &&f, T1 const &t1, T2 const &t2, R &&r)DECL_AND_RETURN(fold_on_zip_impl<pos - 1, T1, T2>()(
std::forward<F>(f), t1, t2, f(std::get<pos>(t1), std::get<pos>(t2), std::forward<R>(r))));
};
template <typename T1, typename T2> struct fold_on_zip_impl<-1, T1, T2> {
template <typename F, typename R> R operator()(F &&f, T1 const &t1, T2 const &t2, R &&r) { return std::forward<R>(r); }
};
template <typename F, typename T1, typename T2, typename R>
auto fold(F &&f, T1 const &t1, T2 const &t2, R &&r)
DECL_AND_RETURN(fold_on_zip_impl<std::tuple_size<T1>::value - 1, T1, T2>()(std::forward<F>(f), t1, t2, std::forward<R>(r)));
#endif
/**
* replace<int ... I>(t,r)
* Given a tuple t, and integers, returns the tuple where the elements at initial position I are replaced by r
*/
template <int I, typename T, typename R> R _get_rpl(T &&x, R &&r, _int<I>) { return std::forward<R>(r); }
template <int I, typename T, typename R> T _get_rpl(T &&x, R &&r, ...) { return std::forward<T>(x); }
template <size_t... Is, typename Tu, typename R, typename AllIndices>
auto _replace_impl(Tu &&tu, R &&r, AllIndices _, std14::index_sequence<Is...>)
RETURN(std::make_tuple(_get_rpl<Is>(std::get<Is>(tu), r, _)...));
template <int... I, typename Tu, typename R>
auto replace(Tu &&tu, R &&r) RETURN(_replace_impl(tu, r, all_indices<I...>(), _get_seq<Tu>()));
/**
* filter<int ... I>(t) :
* Given a tuple t, and integers, returns the tuple where the elements at initial position I are kept.
*/
template <typename Tu, size_t... I> using filter_t = std::tuple<typename std::tuple_element<I, std14::decay_t<Tu>>::type...>;
template <size_t... I, typename Tu> filter_t<Tu, I...> filter(Tu &&tu) {
return filter_t<Tu, I...>(std::get<I>(std::forward<Tu>(tu))...);
}
template <size_t... I, typename Tu> filter_t<Tu, I...> filter(Tu &&tu, std14::index_sequence<I...>) {
return filter_t<Tu, I...>(std::get<I>(std::forward<Tu>(tu))...);
}
/**
* filter_out<int ... I>(t) :
* Given a tuple t, and integers, returns the tuple where the elements at initial position I are dropped.
*/
template <int... I, typename Tu>
AUTO_DECL filter_out(Tu &&tu) RETURN(filter(tu, complement_sequence<std::tuple_size<std14::decay_t<Tu>>::value - 1, I...>()));
template <typename Tu, int... I> using filter_out_t = std14::decay_t<decltype(filter_out<I...>(std::declval<Tu>()))>;
/**
* t : a tuple
* x : anything
* push_back (t,x) -> returns new tuple with x append at the end
*/
template <typename T, typename X>
auto push_back(T &&t, X &&x) RETURN(std::tuple_cat(std::forward<T>(t), std::make_tuple(std::forward<X>(x))));
/**
* t : a tuple
* x : anything
* push_front (t,x) -> returns new tuple with x append at the first position
*/
template <typename T, typename X>
auto push_front(T &&t, X &&x) RETURN(std::tuple_cat(std::make_tuple(std::forward<X>(x)), std::forward<T>(t)));
/// To be rewritten ....
/**
* inverse_filter<int L, int ... I>(t,x)
* Given a tuple t, and integers, returns the tuple R of size L such that filter<I...>(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<int pos, int pos_in, int c, int ... I> struct inverse_filter_impl;
// default case where pos != the first I
template<int pos, int pos_in, int c, int ... I> struct inverse_filter_impl<pos, pos_in, c, pos, I...> {
template<typename TupleIn, typename TupleOut, typename X> auto operator() (TupleIn const & t, TupleOut && out, X const & x) const
DECL_AND_RETURN( inverse_filter_impl<pos+1,pos_in+1,c-1, I...> ()( t, push_back(std::forward<TupleOut>(out),std::get<pos_in>(t)),x));
};
// when pos == first I
template<int pos, int pos_in, int c, int ... I> struct inverse_filter_impl {
template<typename TupleIn, typename TupleOut, typename X> auto operator() (TupleIn const & t, TupleOut && out, X const & x) const
DECL_AND_RETURN( inverse_filter_impl<pos+1,pos_in,c-1, I...> ()( t, push_back(std::forward<TupleOut>(out),x), x));
};
template<int pos, int pos_in, int ... I> struct inverse_filter_impl <pos,pos_in, -1, I...> {
template<typename TupleIn, typename TupleOut, typename X> 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<Tu>::value, "inverse filter : the # of int must be equal to the tuple size !!");
typedef inverse_filter_impl<0,0,L-1, I...> type;
};
template<int L, int ...I, typename Tu, typename X>
auto inverse_filter(Tu const & tu, X const &x) DECL_AND_RETURN ( typename inverse_filter_r_type<Tu, X, L, I...>::type ()(tu, std::make_tuple(),x));
/**
* inverse_filter_out<int ... I>(t,x)
* Given a tuple t, and integers, returns the tuple R such that filter_out<I...>(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<int pos, int pos_in, int c, int ... I> struct inverse_filter_out_impl;
// default case where pos != the first I
template<int pos, int pos_in, int c, int ... I> struct inverse_filter_out_impl {
template<typename TupleIn, typename TupleOut, typename X> auto operator() (TupleIn const & t, TupleOut && out, X const & x) const
DECL_AND_RETURN( inverse_filter_out_impl<pos+1,pos_in+1,c-1, I...> ()( t, push_back(std::forward<TupleOut>(out),std::get<pos_in>(t)),x));
};
// when pos == first I
template<int pos, int pos_in, int c, int ... I> struct inverse_filter_out_impl <pos, pos_in, c, pos, I...> {
template<typename TupleIn, typename TupleOut, typename X> auto operator() (TupleIn const & t, TupleOut && out, X const & x) const
DECL_AND_RETURN( inverse_filter_out_impl<pos+1,pos_in,c-1, I...> ()( t, push_back(std::forward<TupleOut>(out),x), x));
};
template<int pos, int pos_in, int ... I> struct inverse_filter_out_impl <pos,pos_in, -1, I...> {
template<typename TupleIn, typename TupleOut, typename X> TupleOut operator() (TupleIn const &, TupleOut && out, X const &) const {return out;}
};
template<int ...I, typename Tu, typename X>
auto inverse_filter_out(Tu const & tu, X const &x) DECL_AND_RETURN ( inverse_filter_out_impl<0,0,std::tuple_size<Tu>::value+sizeof...(I)-1, I...>()(tu, std::make_tuple(),x));
/*
* print a tuple
*/
inline void _triqs_print_tuple_impl(std::ostream &os) {}
template <typename T0, typename... T> 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 <size_t... Is, typename... T>
void _triqs_print_tuple(std::ostream &os, std::tuple<T...> const &t, std14::index_sequence<Is...>) {
_triqs_print_tuple_impl(os, std::get<Is>(t)...);
}
}
}
namespace std {
template <typename... T> std::ostream &operator<<(std::ostream &os, std::tuple<T...> const &t) {
os << "(";
triqs::tuple::_triqs_print_tuple(os, t, std14::make_index_sequence<sizeof...(T)>());
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 <typename... Args> class tuple : public std::tuple<Args...> {
public:
template <typename... Args2> tuple(Args2 &&... args2) : std::tuple<Args...>(std::forward<Args2>(args2)...) {}
};
}
// minimal hack to get the metaprogramming work with this tuple too....
template <int i, typename... Args>
auto get(c14::tuple<Args...> const &t) DECL_AND_RETURN(std::get<i>(static_cast<std::tuple<Args...>>(t)));
template <typename... Args> class tuple_size<c14::tuple<Args...>> : public tuple_size<std::tuple<Args...>> {};
}