3
0
mirror of https://github.com/triqs/dft_tools synced 2024-12-26 14:23:38 +01:00
dft_tools/triqs/arrays/indexmaps/cuboid/slice.hpp
Olivier Parcollet f2c7d449cc First commit : triqs libs version 1.0 alpha1
for earlier commits, see TRIQS0.x repository.
2013-07-17 19:24:07 +02:00

116 lines
5.8 KiB
C++

/*******************************************************************************
*
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
*
* Copyright (C) 2011 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/>.
*
******************************************************************************/
#ifndef TRIQS_ARRAYS_INDEXMAP_CUBOID_SLICE_H
#define TRIQS_ARRAYS_INDEXMAP_CUBOID_SLICE_H
#include <triqs/utility/count_type_occurrence.hpp>
#include "./slice_traversal_order.hpp"
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
typedef size_t l_type;
typedef std::ptrdiff_t s_type;
template <bool BC> inline void _check_BC ( int N, int ind, size_t B, int ind_min =0) { }
template <> inline void _check_BC<true> (int N, int ind, size_t B, int ind_min) {
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";
}
struct slice_calc { // group in a struct to avoid declaration order issue with the cross call of templates...
template<int N, int P, bool BoundCheck>
static void one_step(LISILOSO, std::ptrdiff_t& offset, size_t R){
_check_BC <BoundCheck> (N, R, li[N]);
offset += R*si[N];
}
template<int N, int P, bool BoundCheck>
static void one_step(LISILOSO, std::ptrdiff_t& offset, range R){
_check_BC<BoundCheck> (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<BoundCheck> (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];
}
template<int N, int P, bool BoundCheck, int EllipsisLength, typename Arg0, typename... Args>
static typename std::enable_if<((EllipsisLength==1) || (!std::is_base_of<ellipsis, Arg0 >::type::value)), void>::type
invoke(LISILOSO, s_type & offset, Arg0 const & arg0, Args const & ... args ) {
constexpr bool dP = (std::is_base_of<range,Arg0>::type::value ? 1 : 0); // Arg0 is range or ellipsis
one_step<N,P,BoundCheck>(li,si,lo,so,offset, arg0);
invoke<N+1,P+dP,BoundCheck,EllipsisLength>(li,si,lo,so, offset, args...);
}
template<int N, int P, bool BoundCheck, int EllipsisLength, typename Arg0, typename... Args>
static typename std::enable_if<((EllipsisLength==0) && std::is_base_of<ellipsis, Arg0 >::type::value), void>::type
invoke(LISILOSO, s_type & offset, Arg0 const & arg0, Args const & ... args ) {
invoke<N,P,BoundCheck,EllipsisLength>(li,si,lo,so, offset, args...);
}
template<int N, int P, bool BoundCheck, int EllipsisLength, typename Arg0, typename... Args>
static typename std::enable_if<((EllipsisLength>1) && std::is_base_of<ellipsis, Arg0 >::type::value), void>::type
invoke(LISILOSO, s_type & offset, Arg0 const & arg0, Args const & ... args ) {
constexpr bool dP = (std::is_base_of<range,Arg0>::type::value ? 1 : 0); // Arg0 is range or ellipsis
one_step<N,P,BoundCheck>(li,si,lo,so,offset, arg0);
invoke<N+1,P+dP,BoundCheck,EllipsisLength-1>(li,si,lo,so, offset, arg0, args...);
}
template<int N, int P, bool BoundCheck, int EllipsisLength> static void invoke(LISILOSO, s_type & offset ) {}
};
#undef LISILOSO
}//namespace cuboid_details
// special case of no argument :
template<int R, ull_t Opt, ull_t To> struct slicer < cuboid::map<R, Opt,To> > { typedef cuboid::map < R, Opt,To > r_type; };
// general case
template<int R, ull_t Opt, ull_t To, typename... Args> struct slicer < cuboid::map<R, Opt,To>, Args...> {
static const unsigned int len = sizeof...(Args);
static constexpr bool has_ellipsis = (count_type_occurrence<ellipsis,Args...>::value>0);
static_assert((count_type_occurrence<ellipsis,Args...>::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
typedef cuboid::map<R,Opt,To> im_t;
static constexpr int Rf = R - count_type_occurrence_not<range,Args...>::value;
static constexpr ull_t To_i = im_t::traversal_order;
// compute a new traversal order, only if there is no ellipsis
// the computation with ellipsis is not yet implemented...
static constexpr ull_t Tof = (has_ellipsis ? 0 : cuboid::slicing_TO_order::sliced_memory_order<To_i,Args...>::value);
typedef cuboid::map < Rf , Opt, Tof> r_type;
#ifndef TRIQS_WORKAROUND_INTEL_COMPILER_BUGS
static_assert(( (has_ellipsis) || (permutations::size(Tof) == Rf)), "Mismatch between Rank and the TraversalOrder");
#endif
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;
cuboid_details::slice_calc::invoke<0,0,flags::bound_check_trait<Opt>::value,EllipsisLength>(&X.lengths()[0],&X.strides()[0],&newlengths[0],&newstrides[0],newstart, args...);
return r_type(std::move(newlengths),std::move(newstrides),newstart);// use move construction ?
};
};
}}}//namespaces triqs::arrays::indexmaps
#endif