/*******************************************************************************
*
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
*
* Copyright (C) 2011-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
namespace triqs {
namespace arrays {
namespace indexmaps {
namespace cuboid_details {
#define LISILOSO l_type const* li, s_type const* si, l_type* lo, s_type* so, int* imap
using l_type = size_t;
using s_type = std::ptrdiff_t;
inline void _check_BC(int N, int ind, size_t B, int ind_min = 0) {
#ifdef TRIQS_ARRAYS_ENFORCE_BOUNDCHECK
if (!((ind >= ind_min) && (ind < int(B))))
TRIQS_ARRAYS_KEY_ERROR << " index " << N << " is out of domain: \n " << ind << " is not within [0," << B << "[\n";
#endif
}
struct slice_calc { // group in a struct to avoid declaration order issue with the cross call of templates...
template static void one_step(LISILOSO, std::ptrdiff_t& offset, size_t R) {
_check_BC(N, R, li[N]);
offset += R * si[N];
imap[N] = -1;
}
template static void one_step(LISILOSO, std::ptrdiff_t& offset, range R) {
_check_BC(N, R.first(), li[N]);
lo[P] = ((R.last() == -1 ? li[N] : R.last()) - R.first() + R.step() - 1) / R.step(); // python behaviour
_check_BC(N, R.first() + (lo[P] != 0 ? (lo[P] - 1) : 0) * R.step(), li[N], -1);
so[P] = si[N] * R.step();
offset += R.first() * si[N];
imap[N] = P;
}
// ellipsis is a total range, we can simplify the computation in that case...
template static void one_step(LISILOSO, std::ptrdiff_t& offset, ellipsis) {
_check_BC(N, 0, li[N]);
lo[P] = li[N];
_check_BC(N, (lo[P] != 0 ? (lo[P] - 1) : 0), li[N], -1);
so[P] = si[N];
imap[N] = P;
}
template
static std14::enable_if_t<((EllipsisLength == 1) || (!std::is_base_of::type::value)), void>
invoke(LISILOSO, s_type& offset, Arg0 const& arg0, Args const&... args) {
constexpr bool dP = (std::is_base_of::type::value ? 1 : 0); // Arg0 is range or ellipsis
one_step(li, si, lo, so, imap, offset, arg0);
invoke(li, si, lo, so, imap, offset, args...);
}
template
static std14::enable_if_t<((EllipsisLength == 0) && std::is_base_of::type::value), void>
invoke(LISILOSO, s_type& offset, Arg0 const& arg0, Args const&... args) {
invoke(li, si, lo, so, imap, offset, args...);
}
template
static std14::enable_if_t<((EllipsisLength > 1) && std::is_base_of::type::value), void>
invoke(LISILOSO, s_type& offset, Arg0 const& arg0, Args const&... args) {
one_step(li, si, lo, so, imap, offset, arg0);
invoke(li, si, lo, so, imap, offset, arg0, args...);
}
template static void invoke(LISILOSO, s_type& offset) {}
};
#undef LISILOSO
} // namespace cuboid_details
// special case of no argument :
template struct slicer> {
using r_type = cuboid::map;
};
// general case
template struct slicer, Args...> {
static const unsigned int len = sizeof...(Args);
static constexpr bool has_ellipsis = (count_type_occurrence::value > 0);
static_assert((count_type_occurrence::value < 2), "Only one ellipsis is permitted");
static_assert((len >= R || has_ellipsis), "Too few arguments in slice");
static_assert((len <= R + (has_ellipsis ? 1 : 0)), "Too many arguments in slice"); // + one to allow an empty ellipsis
using im_t = cuboid::map;
static constexpr int Rf = R - count_type_occurrence_not::value;
// TO DO : compute the new traversal order using the same routine, constexpr, if needed ?
// Af the moment, using simply the C traversal order.
using Tof = void; //_traversal_c;
using r_type = cuboid::map;
static r_type invoke(im_t const& X, Args... args) {
typename r_type::lengths_type newlengths;
typename r_type::strides_type newstrides;
std::ptrdiff_t newstart = X.start_shift();
constexpr int EllipsisLength = R - len + 1;
mini_vector imap(utility::no_init_tag{});
cuboid_details::slice_calc::invoke<0, 0, EllipsisLength>(&X.lengths()[0], &X.strides()[0], &newlengths[0], &newstrides[0],
imap.ptr(), newstart, args...);
if (X.get_memory_layout().is_c()) return r_type(std::move(newlengths), std::move(newstrides), newstart, memory_layout{});
if (X.get_memory_layout().is_fortran()) return r_type(std::move(newlengths), std::move(newstrides), newstart, memory_layout{FORTRAN_LAYOUT});
// Compute the new memory index order
mini_vector p(utility::no_init_tag{});
for (int i = 0, j = 0; j < R; ++j) {
auto k = imap[X.get_memory_layout()[j]];
if (k != -1) p[i++] = k;
}
return r_type(std::move(newlengths), std::move(newstrides), newstart, memory_layout{p, bool()});
};
};
}
}
} // namespaces triqs::arrays::indexmaps