3
0
mirror of https://github.com/triqs/dft_tools synced 2024-12-25 05:43:40 +01:00

tuple tools : simplify

- simplify implementation of several functions.
- clean API, rename, etc...
- add more documentation
This commit is contained in:
Olivier Parcollet 2014-06-06 19:02:43 +02:00
parent 6d12c4b7f6
commit 36a60ce529
15 changed files with 714 additions and 413 deletions

View File

@ -2,17 +2,16 @@
.. _util_tuple: .. _util_tuple:
Tuple compile time tools Tuple tools
============================= =============================
Very useful for lib developers, they fill a missing gap in the std library. Various standard functional operations on tuple (which should be in the STL but are not ...).
They implement various standard functional operations, at compile time,
on tuple...
.. note:: ..
.. note::
Simple measures have shown that these routines are **as fast as native code** (tested on gcc, clang, icc),
due to inlining. They can therefore be used in critical parts of codes. Simple measures have shown that these routines are **as fast as native code** (tested on gcc, clang, icc),
due to inlining. They can therefore be used in critical parts of codes.
apply apply
----------------------------------------------- -----------------------------------------------
@ -21,15 +20,21 @@ apply
Given a function object `f`, and its arguments stored in a tuple `t`, and we want to apply `f` on `t`. Given a function object `f`, and its arguments stored in a tuple `t`, and we want to apply `f` on `t`.
Python equivalent : `f(*t)` *Python equivalent*:
.. code-block:: python
def apply(f,t) :
return f(*t)
*Synopsis* :: *Synopsis* ::
template<typename Function, typename Tuple> auto apply (Function && f, Tuple const & t); template<typename Function, typename Tuple> auto apply (Function && f, Tuple const & t);
*Solution* : *Example* :
.. triqs_example:: ./tupletools_0.cpp .. triqs_example:: ./tupletools_0.cpp
for_each for_each
------------------------------------------------------------------------- -------------------------------------------------------------------------
@ -38,12 +43,204 @@ for_each
Given a function object `f`, we want to apply it to all elements of a tuple `t`. Given a function object `f`, we want to apply it to all elements of a tuple `t`.
Python equivalent : `for x in t : f(x)` *Python equivalent*:
.. code-block:: python
def for_each(t,f) :
for x in t:
f(x)
*Synopsis* :: *Synopsis* ::
template<typename Function, typename Tuple> void for_each(Tuple const & t, Function && f); template<typename Function, typename Tuple> void for_each(Tuple const & t, Function && f);
*Solution* : *Example* :
.. triqs_example:: ./tupletools_1.cpp .. triqs_example:: ./tupletools_1.cpp
for_each_zip
-------------------------------------------------------------------------
*Purpose* : `apply a function for each element of tuple zip (in order)`
*Python equivalent*:
.. code-block:: python
def for_each(f,t0,t1) :
for x0,x1 in itertools.zip(t0,t1):
f(x0,x1)
*Synopsis* ::
template <typename F, typename T0, typename T1> void for_each_zip(F &&f, T0 &&t0, T1 &&t1);
template <typename F, typename T0, typename T1, typename T2> void for_each_zip(F &&f, T0 &&t0, T1 &&t1, T2 &&t2);
*Example* :
.. triqs_example:: ./tupletools_2.cpp
map
-------------------------------------------------------------------------
*Purpose* : `map a function on a tuple to create a new tuple`
*Python equivalent*:
.. code-block:: python
def map(f,t) :
return (f(x) for x in t)
*Synopsis* ::
template <typename T, typename F> auto map(F &&f, T &&t);
*Returns*:
The result is a tuple, of the same length as T, made of the evaluation of f on the elements on T
*Example* :
.. triqs_example:: ./tupletools_3.cpp
fold
-------------------------------------------------------------------------
*Purpose* : `reduction of a tuple with a function`
*Python equivalent*:
.. code-block:: python
def fold(f,t,r) :
return reduce(f,t,r)
*Synopsis* ::
(1) template <typename F, typename T, typename R>
decltype(auto) fold(F &&f, T &&t, R &&r);
(2) template <typename F, typename T0, typename T1, typename R>
decltype(auto) fold(F &&f, T0 &&t0, T1 &&t1, R &&r);
*Returns*::
f(get<N>(t),
f(get<N-1>(t),
...,
f(get<0>(t),r))) (1)
f(get<N>(t0), get<N>(t1),
f(get<N-1>(t0), get<N-1>(t1),
...,
f(get<0>(t0), get<0>(t1), r))) (2)
*Parameters* :
* f : a callable object of signature ::
f(x, r) -> r' (1)
f(x, y, r) -> r' (2)
The return type of f must be a valid last parameter for f (at least for one overload).
* t : a tuple
* t0,t1 : two tuples of the same size
* r : anything that can be a last parameter for f.
* Precondition: everything so that the resulting expression is valid (in particular, f must be called on each tuple elements,
with its return type as last parameter.
.. warning::
The type of the result is not necessarly R : it is automatically deduced from this expression. Cf example.
*Example* :
.. triqs_example:: ./tupletools_4.cpp
reverse
-------------------------------------------------------------------------
*Purpose* : `lazy reverse of a tuple`
*Python equivalent*: None.
*Synopsis* ::
namespace std {
template<typename ... T> TU reverse(std::tuple<T...> && x);
template<typename ... T> TU reverse(std::tuple<T...> & x);
template<typename ... T> TU reverse(std::tuple<T...> const& x);
}
.. warning::
reverse is declared in std:: to benefit from ADL (a bit dangerous, but ok here).
*Returns*:
TU is a tuple like type, that :
* Contains a ref of the original tuple, or the tuple if a && was passed.
* Hence, no copy is ever made.
* Accepts std::get and std::tuple_size, like tuple.
reverse(t) can therefore be used in place of a regular tuple in the algorithms of this section.
*Example* :
.. triqs_example:: ./tupletools_reverse.cpp
called_on_tuple
-------------------------------------------------------------------------
*Purpose* : `Adapting a function to call with a tuple argument and flatten it`
*Python equivalent*:
.. code-block:: python
def called_on_tuple(f) :
return lambda x : f(*x)
*Synopsis* ::
template <typename F> F2 called_on_tuple(F &&f);
*Returns*:
F2 is a function object which adapts the function f for calling on a tuple.
The following call are therefore equivalent::
called_on_tuple(f)( std::tie(x0,x1,x2))
f(x0,x1,x2)
*Example* :
.. triqs_example:: ./tupletools_called.cpp
*Implementation* :
The C++ is simple in fact ::
template <typename F> struct _called_on_tuple {
F _f;
template <typename Tu> decltype(auto) 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)};
}

View File

@ -1,11 +1,11 @@
#include <triqs/utility/tuple_tools.hpp> #include <triqs/utility/tuple_tools.hpp>
#include <iostream> #include <iostream>
int main() { int main() {
auto fun = [](int i, double x, double y, int k) { return 6 * k + i - 1.3 * x + 2 * y; }; auto fun = [](int i, double x, double y, int k) { return 6 * k + i - 1.3 * x + 2 * y; };
auto t = std::make_tuple(1, 2.3, 4.3, 8); auto t = std::make_tuple(1, 2.3, 4.3, 8);
auto res = triqs::tuple::apply(fun, t); auto res = triqs::tuple::apply(fun, t);
std::cout << " f(t) =" << res << std::endl; std::cout << " f(t) =" << res << std::endl;
} }

View File

@ -1,15 +1,10 @@
#include <triqs/utility/tuple_tools.hpp> #include <triqs/utility/tuple_tools.hpp>
#include <iostream> #include <iostream>
struct print_t {
template <typename T> void operator()(T x) { std::cout << x << " "; }
};
int main() { int main() {
auto t = std::make_tuple(1, 2.3, 4.3, 8, "hello"); auto t = std::make_tuple(1, 2.3, 4.3, 8);
triqs::tuple::for_each(t, print_t()); auto l = [](double x) { std::cout << x << " "; };
// C++14 solution : with generic lambda, there is no need to define a print_t ... triqs::tuple::for_each(t, l);
// triqs::tuple::for_each(t, [](auto x) { std::cout<<x<<" ";});
} }

View File

@ -0,0 +1,11 @@
#include <triqs/utility/tuple_tools.hpp>
#include <iostream>
int main() {
auto t1 = std::make_tuple(1, 2.3, 4.3, 8);
auto t2 = std::make_tuple('|','|','|','|');
auto l = [](double x, char c) { std::cout << c << " " << x << " "; };
triqs::tuple::for_each_zip(l, t1, t2);
}

View File

@ -0,0 +1,12 @@
#include <triqs/utility/tuple_tools.hpp>
#include <iostream>
int main() {
auto t = std::make_tuple(1, 2.3, 4.3, 8);
auto l = [](double x) { return -x; };
auto res = triqs::tuple::map(l, t);
std::cout << res << std::endl;
}

View File

@ -0,0 +1,24 @@
#include <triqs/utility/tuple_tools.hpp>
#include <iostream>
int main() {
auto t = std::make_tuple(1, 2.3, 4.3, 8);
// a simple example : make a sum
auto f = [](double x, double r) { return x + r; };
auto res = triqs::tuple::fold(f, t, 0); // <-- R is int but res is a double (from f's return type).
std::cout << res << std::endl;
// the types of x and r may be different
triqs::tuple::fold([](double x, std::ostream & os)->std::ostream & { return os << "|" << x; }, t, std::cout);
// example with zip
auto t0 = std::make_tuple(1, 2, 3, 4);
auto t1 = std::make_tuple(1, -1, 1, -1);
auto res2 = triqs::tuple::fold([](double x, double y, double r) { return y * x + r; }, t0, t1, 0);
std::cout << "\n " << res2 << std::endl;
}

View File

@ -0,0 +1,11 @@
#include <triqs/utility/tuple_tools.hpp>
#include <iostream>
int main() {
auto fun = [](int i, double x, double y, int k) { return 6 * k + i - 1.3 * x + 2 * y; };
auto t = std::make_tuple(1, 2.3, 4.3, 8);
auto res = triqs::tuple::called_on_tuple(fun)(t);
std::cout << " f(t) =" << res << std::endl;
}

View File

@ -0,0 +1,11 @@
#include <triqs/utility/tuple_tools.hpp>
#include <iostream>
int main() {
auto t = std::make_tuple(1, 2.3, 4.3, 8);
auto l = [](double x) { std::cout << x << " "; };
triqs::tuple::for_each(t, l);
std::cout << std::endl;
triqs::tuple::for_each(reverse(t), l);
}

View File

@ -37,6 +37,9 @@ try {
auto G_w_wn_view = G_w_wn(); auto G_w_wn_view = G_w_wn();
auto G_w_wn_sl0_a = partial_eval<0>(G_w_wn(), 8); auto G_w_wn_sl0_a = partial_eval<0>(G_w_wn(), 8);
//decltype(G_w_wn_sl0_a.mesh())::zozo();
static_assert(std::is_same<typename std::remove_reference<decltype(G_w_wn_sl0_a.mesh())>::type, const gf_mesh<imfreq>>::value, "oops"); static_assert(std::is_same<typename std::remove_reference<decltype(G_w_wn_sl0_a.mesh())>::type, const gf_mesh<imfreq>>::value, "oops");
//auto G_w_wn_curry0_a = curry0(G_w_wn); //auto G_w_wn_curry0_a = curry0(G_w_wn);
//auto G_w_wn_sl0_a = slice_mesh0(G_w_wn(), 8); //auto G_w_wn_sl0_a = slice_mesh0(G_w_wn(), 8);

View File

@ -19,7 +19,6 @@
* *
******************************************************************************/ ******************************************************************************/
#include <triqs/utility/tuple_tools.hpp> #include <triqs/utility/tuple_tools.hpp>
#include <iostream>
#include <cmath> #include <cmath>
#include <stdexcept> #include <stdexcept>
#include <functional> #include <functional>
@ -30,10 +29,6 @@ struct fun {
double operator()(int i, double x, double y, int k) { return 6*k + i - 1.3*x + 2*y;} double operator()(int i, double x, double y, int k) { return 6*k + i - 1.3*x + 2*y;}
}; };
struct fun2 {
double operator()(double x, double y) { return x+y;}
};
struct print_t { struct print_t {
template<typename T> template<typename T>
void operator()(T x) { std::cerr << x << " "; } void operator()(T x) { std::cerr << x << " "; }
@ -74,12 +69,8 @@ int main(int argc, char **argv) {
} }
{ {
auto r = triqs::tuple::apply_on_zip(fun2(),t1,t2); auto r = triqs::tuple::map_on_zip_v2([](double x, double y) { return x + y; }, t1, t2);
std::cerr << " [f(a,b) for (a,b) in zip(t1,t2)] =" std::cerr << " [f(a,b) for (a,b) in zip(t1,t2)] =" << r << std::endl;
<< std::get<0>(r) << " "
<< std::get<1>(r) << " "
<< std::get<2>(r) << " "
<< std::get<3>(r) << std::endl;
} }
std::cerr << " ----- fold ----"<< std::endl ; std::cerr << " ----- fold ----"<< std::endl ;
@ -103,7 +94,7 @@ int main(int argc, char **argv) {
} }
{ {
auto res = triqs::tuple::fold_on_zip([](double x, double y, double r) { return x+ 2*y +r;}, t1,t2, 0); auto res = triqs::tuple::fold([](double x, double y, double r) { return x+ 2*y +r;}, t1,t2,0);
std::cerr << " " << res << std::endl ; std::cerr << " " << res << std::endl ;
if ( std::abs((res - 35.6)) > 1.e-13) throw std::runtime_error(" "); if ( std::abs((res - 35.6)) > 1.e-13) throw std::runtime_error(" ");
} }
@ -161,9 +152,6 @@ int main(int argc, char **argv) {
auto t2= std::make_tuple(0,1); auto t2= std::make_tuple(0,1);
std::cout << "filter out "<< t2 << triqs::tuple::filter_out<0>(t2)<< std::endl; std::cout << "filter out "<< t2 << triqs::tuple::filter_out<0>(t2)<< std::endl;
typedef typename triqs::tuple::filter_t_tr< decltype(t), 0,2,3>::type TY;
static_assert(std::is_same<TY, decltype(triqs::tuple::filter<0,2,3>(t))>::value, "EEE");
} }
{ // filter { // filter

View File

@ -63,7 +63,7 @@ namespace gfs {
/// Conversions point <-> index <-> linear_index /// Conversions point <-> index <-> linear_index
typename domain_t::point_t index_to_point(index_t const &ind) const { typename domain_t::point_t index_to_point(index_t const &ind) const {
domain_pt_t res; domain_pt_t res;
triqs::tuple::apply_on_zip(_aux1(), res, m_tuple, ind); triqs::tuple::map_on_zip(_aux1(), res, m_tuple, ind);
return res; return res;
} }
@ -77,10 +77,8 @@ namespace gfs {
public: public:
/// Flattening index to linear : index[0] + component[0].size * (index[1] + component[1].size* (index[2] + ....)) /// Flattening index to linear : index[0] + component[0].size * (index[1] + component[1].size* (index[2] + ....))
size_t index_to_linear(index_t const &ii) const { size_t index_to_linear(index_t const &ii) const {
return triqs::tuple::fold_on_zip(_aux2(), reverse(m_tuple), reverse(ii), size_t(0)); return triqs::tuple::fold(_aux2(), reverse(m_tuple), reverse(ii), size_t(0));
} }
// size_t index_to_linear(index_t const & ii) const { return triqs::tuple::fold_on_zip([](auto const &m, auto const &i, auto R)
//{return m.index_to_linear(i) + R * m.size();} , m_tuple, ii, size_t(0)); }
private: private:
struct _aux3 { struct _aux3 {
@ -92,7 +90,7 @@ namespace gfs {
public: public:
/// Flattening index to linear : index[0] + component[0].size * (index[1] + component[1].size* (index[2] + ....)) /// Flattening index to linear : index[0] + component[0].size * (index[1] + component[1].size* (index[2] + ....))
size_t mp_to_linear(m_pt_tuple_t const &mp) const { size_t mp_to_linear(m_pt_tuple_t const &mp) const {
return triqs::tuple::fold_on_zip(_aux3(), reverse(m_tuple), reverse(mp), size_t(0)); return triqs::tuple::fold(_aux3(), reverse(m_tuple), reverse(mp), size_t(0));
} }
// //
@ -134,8 +132,8 @@ namespace gfs {
public: public:
mesh_point_t() = default; mesh_point_t() = default;
mesh_point_t(mesh_product const &m_, index_t index_) mesh_point_t(mesh_product const &m_, index_t index_)
: m(&m_), _c(triqs::tuple::apply_on_zip(F2(), m_.m_tuple, index_)), _atend(false) {} : m(&m_), _c(triqs::tuple::map_on_zip(F2(), m_.m_tuple, index_)), _atend(false) {}
mesh_point_t(mesh_product const &m_) : m(&m_), _c(triqs::tuple::apply_on_tuple(F1(), m_.m_tuple)), _atend(false) {} mesh_point_t(mesh_product const &m_) : m(&m_), _c(triqs::tuple::map(F1(), m_.m_tuple)), _atend(false) {}
m_pt_tuple_t const &components_tuple() const { return _c; } m_pt_tuple_t const &components_tuple() const { return _c; }
size_t linear_index() const { return m->mp_to_linear(_c); } size_t linear_index() const { return m->mp_to_linear(_c); }
const mesh_product *mesh() const { return m; } const mesh_product *mesh() const { return m; }

View File

@ -53,25 +53,25 @@ namespace gfs {
typename domain_t::point_t index_to_point(index_t const &ind) const { typename domain_t::point_t index_to_point(index_t const &ind) const {
domain_pt_t res; domain_pt_t res;
auto l = [](auto &p, auto const &m, auto const &i) { p = m.index_to_point(i); }; auto l = [](auto &p, auto const &m, auto const &i) { p = m.index_to_point(i); };
triqs::tuple::apply_on_zip(l, res, m_tuple, ind); triqs::tuple::map_on_zip(l, res, m_tuple, ind);
return res; return res;
} }
/// Flattening index to linear : index[0] + component[0].size * (index[1] + component[1].size* (index[2] + ....)) /// Flattening index to linear : index[0] + component[0].size * (index[1] + component[1].size* (index[2] + ....))
size_t index_to_linear(index_t const &ii) const { size_t index_to_linear(index_t const &ii) const {
auto l = [](auto const &m, auto const &i, size_t R) { return m.index_to_linear(i) + R * m.size(); }; auto l = [](auto const &m, auto const &i, size_t R) { return m.index_to_linear(i) + R * m.size(); };
return triqs::tuple::fold_on_zip(l,reverse(m_tuple), reverse(ii), size_t(0)); return triqs::tuple::fold(l, reverse(m_tuple), reverse(ii), size_t(0));
} }
/// Flattening index to linear : index[0] + component[0].size * (index[1] + component[1].size* (index[2] + ....)) /// Flattening index to linear : index[0] + component[0].size * (index[1] + component[1].size* (index[2] + ....))
size_t mp_to_linear(m_pt_tuple_t const &mp) const { size_t mp_to_linear(m_pt_tuple_t const &mp) const {
auto l = [](auto const &m, auto const &p, size_t R) { return p.linear_index() + R * m.size(); }; auto l = [](auto const &m, auto const &p, size_t R) { return p.linear_index() + R * m.size(); };
return triqs::tuple::fold_on_zip(l, reverse(m_tuple), reverse(mp), size_t(0)); return triqs::tuple::fold(l, reverse(m_tuple), reverse(mp), size_t(0));
} }
utility::mini_vector<size_t, dim> shape() const { utility::mini_vector<size_t, dim> shape() const {
utility::mini_vector<size_t, dim> res; utility::mini_vector<size_t, dim> res;
auto l = [&res](auto const &m, int i) mutable { res[i] = m.size(); }; auto l = [&res](int i, auto const &m) mutable { res[i] = m.size(); };
triqs::tuple::for_each_enumerate(m_tuple, l); triqs::tuple::for_each_enumerate(m_tuple, l);
return res; return res;
} }
@ -97,9 +97,9 @@ namespace gfs {
mesh_point_t() = default; mesh_point_t() = default;
mesh_point_t(mesh_product const &m_, index_t index_) mesh_point_t(mesh_product const &m_, index_t index_)
: m(&m_) : m(&m_)
, _c(triqs::tuple::apply_on_zip([](auto const & m, auto const & i) { return m[i]; }, m_.m_tuple, index_)) , _c(triqs::tuple::map_on_zip([](auto const & m, auto const & i) { return m[i]; }, m_.m_tuple, index_))
, _atend(false) {} , _atend(false) {}
mesh_point_t(mesh_product const &m_) : m(&m_), _c(triqs::tuple::apply_on_tuple(F1(), m_.m_tuple)), _atend(false) {} mesh_point_t(mesh_product const &m_) : m(&m_), _c(triqs::tuple::map(F1(), m_.m_tuple)), _atend(false) {}
m_pt_tuple_t const &components_tuple() const { return _c; } m_pt_tuple_t const &components_tuple() const { return _c; }
size_t linear_index() const { return m->mp_to_linear(_c); } size_t linear_index() const { return m->mp_to_linear(_c); }
const mesh_product *mesh() const { return m; } const mesh_product *mesh() const { return m; }
@ -145,21 +145,21 @@ namespace gfs {
/// Write into HDF5 /// Write into HDF5
friend void h5_write(h5::group fg, std::string subgroup_name, mesh_product const &m) { friend void h5_write(h5::group fg, std::string subgroup_name, mesh_product const &m) {
h5::group gr = fg.create_group(subgroup_name); h5::group gr = fg.create_group(subgroup_name);
auto l = [gr](auto const &m, int N) { h5_write(gr, "MeshComponent" + std::to_string(N), m); }; auto l = [gr](int N, auto const &m) { h5_write(gr, "MeshComponent" + std::to_string(N), m); };
triqs::tuple::for_each_enumerate(m.components(), l); triqs::tuple::for_each_enumerate(m.components(), l);
} }
/// Read from HDF5 /// Read from HDF5
friend void h5_read(h5::group fg, std::string subgroup_name, mesh_product &m) { friend void h5_read(h5::group fg, std::string subgroup_name, mesh_product &m) {
h5::group gr = fg.open_group(subgroup_name); h5::group gr = fg.open_group(subgroup_name);
auto l = [gr](auto &m, int N) { h5_read(gr, "MeshComponent" + std::to_string(N), m); }; auto l = [gr](int N, auto &m) { h5_read(gr, "MeshComponent" + std::to_string(N), m); };
triqs::tuple::for_each_enumerate(m.components(), l); triqs::tuple::for_each_enumerate(m.components(), l);
} }
/// BOOST Serialization /// BOOST Serialization
friend class boost::serialization::access; friend class boost::serialization::access;
template <class Archive> void serialize(Archive &ar, const unsigned int version) { template <class Archive> void serialize(Archive &ar, const unsigned int version) {
auto l = [&ar](auto &m, int N) { ar &TRIQS_MAKE_NVP("MeshComponent" + std::to_string(N), m); }; auto l = [&ar](int N, auto &m) { ar &TRIQS_MAKE_NVP("MeshComponent" + std::to_string(N), m); };
triqs::tuple::for_each_enumerate(m_tuple, l); triqs::tuple::for_each_enumerate(m_tuple, l);
} }

View File

@ -164,7 +164,7 @@ namespace gfs {
{ {
static constexpr int R = sizeof...(Args); static constexpr int R = sizeof...(Args);
// build the evaluators, as a tuple of ( evaluator<Ms> ( mesh_component, args)) // build the evaluators, as a tuple of ( evaluator<Ms> ( mesh_component, args))
triqs::tuple::call_on_zip(_poly_lambda(), evals, g->mesh().components(), std::make_tuple(args...)); triqs::tuple::for_each_zip(_poly_lambda(), evals, g->mesh().components(), std::make_tuple(args...));
return std::get<R - 1>(evals)(make_binder<R - 2>(g, std::make_tuple(), evals)); return std::get<R - 1>(evals)(make_binder<R - 2>(g, std::make_tuple(), evals));
} }
}; };

View File

@ -26,6 +26,33 @@
// backward compat. C++11 compilers. // backward compat. C++11 compilers.
// new stuff in // new stuff in
// C++14 detection in gcc (4.9 like recent clang).
#if __cplusplus > 201103L
#ifndef __cpp_generic_lambdas
#define __cpp_generic_lambdas
#endif
#ifndef __cpp_decltype_auto
#define __cpp_decltype_auto
#endif
#ifndef __cpp_return_type_deduction
#define __cpp_return_type_deduction
#endif
#endif
// C++11 workaround
#if not defined(__cpp_return_type_deduction) or not defined(__cpp_decltype_auto)
#define TRIQS_C11
#define AUTO_DECL auto
#define RETURN(X,...) ->decltype(X) { __VA_ARGS__; return X;}
#else
#define AUTO_DECL decltype(auto)
#define RETURN(X,...) { __VA_ARGS__; return X;}
#endif
namespace std { namespace std {
namespace c14 { namespace c14 {
@ -130,3 +157,6 @@ namespace std {
namespace std14 { namespace std14 {
using namespace std::c14; using namespace std::c14;
} }

View File

@ -2,7 +2,7 @@
* *
* TRIQS: a Toolbox for Research in Interacting Quantum Systems * TRIQS: a Toolbox for Research in Interacting Quantum Systems
* *
* Copyright (C) 2013 by O. Parcollet * Copyright (C) 2012-2014 by O. Parcollet
* *
* TRIQS is free software: you can redistribute it and/or modify it under the * 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 * terms of the GNU General Public License as published by the Free Software
@ -18,331 +18,379 @@
* TRIQS. If not, see <http://www.gnu.org/licenses/>. * TRIQS. If not, see <http://www.gnu.org/licenses/>.
* *
******************************************************************************/ ******************************************************************************/
#ifndef TRIQS_UTILITY_TUPLE_TOOLS_H #pragma once
#define TRIQS_UTILITY_TUPLE_TOOLS_H
#include<triqs/utility/macros.hpp> #include<triqs/utility/macros.hpp>
#include <tuple>
#include "./c14.hpp" #include "./c14.hpp"
#include <sstream> #include <tuple>
#include <ostream>
// adding to the std lib the reversed lazy tuple... // adding to the std lib the reversed lazy tuple...
// overloading & specializing only the functions needed here. // overloading & specializing only the functions needed here.
namespace std { namespace std {
// Reverse
template<typename TU> struct _triqs_reversed_tuple {TU _x;}; 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 {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...>&> 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<typename ... T> _triqs_reversed_tuple<std::tuple<T...>const &> reverse(std::tuple<T...> const & x) { return {x};}
template<int pos, typename TU> auto get(_triqs_reversed_tuple<TU> const & t) template<int pos, typename TU> AUTO_DECL get(_triqs_reversed_tuple<TU> const & t)
DECL_AND_RETURN(std::get<std::tuple_size<std14::decay_t<TU>>::value-1-pos>(t._x)); RETURN(std::get<std::tuple_size<std14::decay_t<TU>>::value-1-pos>(t._x));
template<int pos, typename TU> auto get(_triqs_reversed_tuple<TU> & t) template<int pos, typename TU> AUTO_DECL get(_triqs_reversed_tuple<TU> & t)
DECL_AND_RETURN(std::get<std::tuple_size<std14::decay_t<TU>>::value-1-pos>(t._x)); RETURN(std::get<std::tuple_size<std14::decay_t<TU>>::value-1-pos>(t._x));
template<int pos, typename TU> auto get(_triqs_reversed_tuple<TU> && t) template<int pos, typename TU> AUTO_DECL get(_triqs_reversed_tuple<TU> && t)
DECL_AND_RETURN(std::get<std::tuple_size<std14::decay_t<TU>>::value-1-pos>(move(t)._x)); 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)...};
}
template<typename TU> class tuple_size<_triqs_reversed_tuple<TU>> : public tuple_size<std14::decay_t<TU>>{};
} }
namespace triqs { namespace tuple { 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 * t : a tuple
* x : anything * x : anything
* push_back (t,x) -> returns new tuple with x append at the end * push_back (t,x) -> returns new tuple with x append at the end
*/ */
template<typename T, typename X> template <typename T, typename X>
auto push_back(T && t, X &&x) DECL_AND_RETURN ( std::tuple_cat(std::forward<T>(t),std::make_tuple(std::forward<X>(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 * t : a tuple
* x : anything * x : anything
* push_front (t,x) -> returns new tuple with x append at the first position * push_front (t,x) -> returns new tuple with x append at the first position
*/ */
template<typename T, typename X> template <typename T, typename X>
auto push_front(T && t, X &&x) DECL_AND_RETURN ( std::tuple_cat(std::make_tuple(std::forward<X>(x)),std::forward<T>(t))); 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 ....
/** /**
* apply(f, t) * inverse_filter<int L, int ... I>(t,x)
* f : a callable object * Given a tuple t, and integers, returns the tuple R of size L such that filter<I...>(R) == t
* t a tuple
* Returns : f(t[0], t[1], ...)
* Equivalent to f(*t) in python ....
*/
template<int pos> struct apply_impl {
template<typename F, typename T, typename ... Args>
auto operator()(F && f, T const & t, Args && ... args)
DECL_AND_RETURN( apply_impl<pos-1>()(std::forward<F>(f),t, std::get<pos>(t), std::forward<Args>(args)...));
};
template<> struct apply_impl<-1> {
template<typename F, typename T, typename ... Args>
auto operator()(F && f, T const & t, Args && ... args) DECL_AND_RETURN( std::forward<F>(f)(std::forward<Args>(args)...));
};
template<typename F, typename T>
auto apply (F && f, T const & t) DECL_AND_RETURN( apply_impl<std::tuple_size<T>::value-1>()(std::forward<F>(f),t));
//template <typename T, typename ReturnType, typename... Args>
//ReturnType apply( ReturnType(*f)(Args...), T const & t) { return apply([f](Args const & ... args) { return (*f)(args...);} ,t);}
/**
* apply_construct<F>(t)
* F : a class
* t a tuple
* Returns : F { t[0], t[1]}
*/
template<int pos, typename F, typename T> struct apply_construct_impl {
template<typename ... Args>
auto operator()(T const & t, Args && ... args)
DECL_AND_RETURN( apply_construct_impl<pos-1,F,T>()(t, std::get<pos>(t), std::forward<Args>(args)...));
};
template<typename F, typename T> struct apply_construct_impl<-1,F,T> {
template<typename ... Args>
auto operator()(T const & t, Args && ... args) DECL_AND_RETURN( F{std::forward<Args>(args)...});
};
template<typename F, typename T>
auto apply_construct (T const & t) DECL_AND_RETURN( apply_construct_impl<std::tuple_size<T>::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<int pos> struct for_each_impl {
template<typename T, typename F>
void operator()(T const & t, F && f) {
f(std::get<std::tuple_size<T>::value-1-pos>(t));
for_each_impl<pos-1>()(t, f);
}
};
template<>
struct for_each_impl<0> {
template<typename T, typename F>
void operator() (T const & t, F && f) { f(std::get<std::tuple_size<T>::value-1>(t)); }
};
template<typename T, typename F>
void for_each(T const & t, F && f) {
for_each_impl<std::tuple_size<T>::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<int pos> struct for_each_enumerate_impl {
template<typename T, typename F>
void operator()(T & t, F && f) {
f(std::get<std::tuple_size<std::c14::decay_t<T>>::value-1-pos>(t),std::tuple_size<T>::value-1-pos);
for_each_enumerate_impl<pos-1>()(t, f);
}
};
template<>
struct for_each_enumerate_impl<0> {
template<typename T, typename F>
void operator() (T & t, F && f) { f(std::get<std::tuple_size<std::c14::decay_t<T>>::value-1>(t), std::tuple_size<std::c14::decay_t<T>>::value-1); }
};
template<typename T, typename F>
void for_each_enumerate(T & t, F && f) {
for_each_enumerate_impl<std::tuple_size<std::c14::decay_t<T>>::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<int pos> struct apply_on_tuple_impl {
template<typename F, typename T1, typename ... Args>
auto operator()(F && f, T1 && t1, Args && ... args)
DECL_AND_RETURN( apply_on_tuple_impl<pos-1>()(std::forward<F>(f),std::forward<T1>(t1), f(std::get<pos>(t1)), std::forward<Args>(args)...));
};
template<> struct apply_on_tuple_impl<-1> {
template<typename F, typename T1, typename ... Args>
auto operator()(F && f, T1 && t1, Args && ... args) DECL_AND_RETURN( std::make_tuple(std::forward<Args>(args)...));
};
template<typename F, typename T1>
auto apply_on_tuple (F && f,T1 && t1) DECL_AND_RETURN( apply_on_tuple_impl<std::tuple_size<std14::decay_t<T1>>::value-1>()(std::forward<F>(f),std::forward<T1>(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<int pos> struct apply_on_zip_impl {
template<typename F, typename T1, typename T2, typename ... Args>
auto operator()(F && f, T1 && t1, T2 && t2, Args && ... args)
DECL_AND_RETURN( apply_on_zip_impl<pos-1>()(std::forward<F>(f),std::forward<T1>(t1), std::forward<T2>(t2), f(std::get<pos>(t1),std::get<pos>(t2)), std::forward<Args>(args)...));
};
template<> struct apply_on_zip_impl<-1> {
template<typename F, typename T1, typename T2, typename ... Args>
auto operator()(F && f, T1 && t1, T2 && t2, Args && ... args) DECL_AND_RETURN( std::make_tuple(std::forward<Args>(args)...));
};
template<typename F, typename T1, typename T2>
auto apply_on_zip (F && f,T1 && t1, T2 && t2) DECL_AND_RETURN( apply_on_zip_impl<std::tuple_size<std14::decay_t<T1>>::value-1>()(std::forward<F>(f),std::forward<T1>(t1),std::forward<T2>(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<int pos> struct apply_on_zip3_impl {
template<typename F, typename T1, typename T2, typename T3, typename ... Args>
auto operator()(F && f, T1 && t1, T2 && t2, T3 && t3, Args && ... args)
DECL_AND_RETURN( apply_on_zip3_impl<pos-1>()(std::forward<F>(f),std::forward<T1>(t1), std::forward<T2>(t2), std::forward<T3>(t3),
f(std::get<pos>(t1),std::get<pos>(t2),std::get<pos>(t3)), std::forward<Args>(args)...));
};
template<> struct apply_on_zip3_impl<-1> {
template<typename F, typename T1, typename T2, typename T3,typename ... Args>
auto operator()(F && f, T1 && t1, T2 && t2, T3 && t3, Args && ... args) DECL_AND_RETURN( std::make_tuple(std::forward<Args>(args)...));
};
template<typename F, typename T1, typename T2, typename T3>
auto apply_on_zip (F && f,T1 && t1, T2 && t2, T3 && t3) DECL_AND_RETURN( apply_on_zip3_impl<std::tuple_size<typename std::remove_const<typename std::remove_reference<T1>::type>::type>::value-1>()(std::forward<F>(f),std::forward<T1>(t1),std::forward<T2>(t2),std::forward<T3>(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<int pos> struct call_on_zip3_impl {
template<typename F, typename T1, typename T2, typename T3>
void operator()(F && f, T1 && t1, T2 && t2, T3 && t3) {
f(std::get<pos>(std::forward<T1>(t1)),std::get<pos>(std::forward<T2>(t2)),std::get<pos>(std::forward<T3>(t3)));
call_on_zip3_impl<pos-1>()(std::forward<F>(f),std::forward<T1>(t1), std::forward<T2>(t2), std::forward<T3>(t3));
}
};
template<> struct call_on_zip3_impl<-1> {
template<typename F, typename T1, typename T2, typename T3> void operator()(F && f, T1 && t1, T2 && t2, T3 && t3){}
};
template<typename F, typename T1, typename T2, typename T3>
void call_on_zip (F && f,T1 && t1, T2 && t2, T3 && t3) {
call_on_zip3_impl<std::tuple_size<typename std::remove_reference<T1>::type>::value-1>()(std::forward<F>(f),std::forward<T1>(t1),std::forward<T2>(t2),std::forward<T3>(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<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)));
//template<typename F, typename T, typename R>
// auto fold (F && f,T const & t, R && r) DECL_AND_RETURN( fold_impl<std::tuple_size<T>::value,std::tuple_size<T>::value-1,T const>()(std::forward<F>(f),t,std::forward<R>(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<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_on_zip (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)));
/**
* filter<int ... I>(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<int pos, int c, int ... I> struct filter_impl;
// default case where pos != the first I : increase pos
template<int pos, int c, int ... I> struct filter_impl : filter_impl<pos+1, c-1, I...> {};
// when pos == first I
template<int pos, int c, int ... I> struct filter_impl<pos, c, pos, I...> {
template<typename TupleIn, typename TupleOut> auto operator() (TupleIn const & t, TupleOut && out) const
DECL_AND_RETURN( filter_impl<pos+1,c-1, I...>() ( t, push_back(std::forward<TupleOut>(out),std::get<pos>(t))));
};
template<int pos, int ... I> struct filter_impl <pos,-1, I...> {
template<typename TupleIn, typename TupleOut> TupleOut operator() (TupleIn const & t, TupleOut && out) const {return out;}
};
template<int ...I, typename Tu>
auto filter(Tu const & tu) DECL_AND_RETURN ( filter_impl<0,std::tuple_size<Tu>::value-1, I...>()(tu, std::make_tuple()));
template<typename Tu,int ...I> struct filter_t_tr : std::result_of< filter_impl<0,std::tuple_size<Tu>::value-1, I...>( Tu, std::tuple<>)>{};
template<typename Tu,int ...I> using filter_t = typename filter_t_tr<Tu,I...>::type;
/**
* filter_out<int ... I>(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<int pos, int c, int ... I> struct filter_out_impl;
// default case where pos != the first I : increase pos
template<int pos, int c, int ... I> struct filter_out_impl<pos, c, pos, I...> : filter_out_impl<pos+1, c-1, I...> {};
// when pos == first I
template<int pos, int c, int ... I> struct filter_out_impl {
template<typename TupleIn, typename TupleOut> auto operator() (TupleIn const & t, TupleOut && out) const
DECL_AND_RETURN( filter_out_impl<pos+1,c-1, I...> ()( t, push_back(std::forward<TupleOut>(out),std::get<pos>(t))));
};
template<int pos, int ... I> struct filter_out_impl <pos,-1, I...> {
template<typename TupleIn, typename TupleOut> TupleOut operator() (TupleIn const & t, TupleOut && out) const {return out;}
};
template<int ...I, typename Tu>
auto filter_out(Tu const & tu) DECL_AND_RETURN ( filter_out_impl<0,std::tuple_size<Tu>::value-1, I...>()(tu, std::make_tuple()));
template<typename Tu,int ...I> struct filter_out_t_tr : std::result_of< filter_out_impl<0,std::tuple_size<Tu>::value-1, I...>( Tu, std::tuple<>)>{};
template<typename Tu,int ...I> using filter_out_t = typename filter_out_t_tr<Tu,I...>::type;
/**
* 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. * and the missing position are filled with object x.
* Precondition (static_assert : sizeof...(I)==size of t) * Precondition (static_assert : sizeof...(I)==size of t)
* and max (I) < L * and max (I) < L
@ -368,7 +416,7 @@ namespace triqs { namespace tuple {
}; };
// put out for clearer error message // put out for clearer error message
template< typename Tu, typename X, int L, int ...I> struct inverse_filter_r_type { 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 !!"); 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; typedef inverse_filter_impl<0,0,L-1, I...> type;
}; };
@ -376,9 +424,9 @@ namespace triqs { namespace tuple {
template<int L, int ...I, typename Tu, typename X> 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)); 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) * inverse_filter_out<int ... I>(t,x)
* Given a tuple t, and integers, returns the tuple R such that filter_out<I...>(R) == t * 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. * and the missing position are filled with object x.
*/ */
@ -386,7 +434,7 @@ namespace triqs { namespace tuple {
template<int pos, int pos_in, int c, int ... I> struct inverse_filter_out_impl; template<int pos, int pos_in, int c, int ... I> struct inverse_filter_out_impl;
// default case where pos != the first I // default case where pos != the first I
template<int pos, int pos_in, int c, int ... I> struct inverse_filter_out_impl { 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 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)); 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));
}; };
@ -404,72 +452,45 @@ namespace triqs { namespace tuple {
template<int ...I, typename Tu, typename X> 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)); 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));
/**
* 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
*/
// pos = position in the tuple, c : counter tuplesize-1 ->0, I : position to filter
template<int pos, int c, int ... I> struct replace_impl;
// default case where pos != the first I : increase pos
template<int pos, int c, int ... I> struct replace_impl<pos, c, pos, I...> {
template<typename TupleIn, typename TupleOut, typename R> auto operator() (TupleIn const & t, TupleOut && out, R const & r) const
DECL_AND_RETURN( replace_impl<pos+1,c-1, I...> ()( t, push_back(std::forward<TupleOut>(out),r),r));
};
// when pos == first I
template<int pos, int c, int ... I> struct replace_impl {
template<typename TupleIn, typename TupleOut, typename R> auto operator() (TupleIn const & t, TupleOut && out, R const & r) const
DECL_AND_RETURN( replace_impl<pos+1,c-1, I...> ()( t, push_back(std::forward<TupleOut>(out),std::get<pos>(t)), r));
};
template<int pos, int ... I> struct replace_impl <pos,-1, I...> {
template<typename TupleIn, typename TupleOut, typename R> TupleOut operator() (TupleIn const & t, TupleOut && out, R const & r) const {return out;}
};
template<int ...I, typename Tu, typename R>
auto replace(Tu const & tu, R const &r) DECL_AND_RETURN ( replace_impl<0,std::tuple_size<Tu>::value-1, I...>()(tu, std::make_tuple(),r));
/* /*
* print a tuple * print a tuple
*/ */
template<int a, int b> struct __s {}; inline void _triqs_print_tuple_impl(std::ostream &os) {}
template<int L, typename T> void print_tuple_impl (std::ostream& os, T const& t, std::integral_constant<int,-1> ) {} template <typename T0, typename... T> void _triqs_print_tuple_impl(std::ostream &os, T0 const &x0, T const &... x) {
template<int L, int rpos, typename T> void print_tuple_impl (std::ostream& os, T const& t, std::integral_constant<int,rpos> ) { os << x0;
os << std::get<L-rpos-1>(t); if (sizeof...(T) > 0) os << ',';
if (rpos>0) os << ','; _triqs_print_tuple_impl(os, x...);
print_tuple_impl<L>(os, t, std::integral_constant<int,rpos-1>());
} }
}}
namespace std { template <size_t... Is, typename... T>
template<typename ... T> std::ostream & operator << (std::ostream & os, std::tuple<T...> const & t) { void _triqs_print_tuple(std::ostream &os, std::tuple<T...> const &t, std14::index_sequence<Is...>) {
os << "("; _triqs_print_tuple_impl(os, std::get<Is>(t)...);
constexpr int L = sizeof...(T);
triqs::tuple::print_tuple_impl<L>(os,t,std::integral_constant<int,L-1>());
return os << ")";
} }
} }
}
namespace std { namespace std {
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...>> {};
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 << ")";
} }
#endif // 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...>> {};
}