#include "mutli_range.h" namespace MultiArrayTools { /******************* * MultiIndexBase * *******************/ namespace { template IndefinitIndexBase& getIndex(MultiIndex& in, size_t n) { if(n == N){ return in.getIndex(); } else { return getIndex(in, n); } } template IndefinitIndexBase& getIndex(MultiIndex& in, size_t n) { return in.getIndex<0>(); } template size_t evaluate_x(const MultiIndex& index) { const auto& subIndex = index.getIndex(); return evaluate_x(index) * subIndex.size() + subIndex.pos(); } template size_t evaluate_x<0>(const MultiIndex& index) { const auto& subIndex = index.getIndex<0>(); return subIndex.pos(); } template inline void plus(MultiIndex& index, size_t digit, int num) { IndefinitIndexBase& si = index.getIndex(digit); si.setPos( si.pos() + num ); size_t oor = si.outOfRange(); if(oor and digit != MultiIndex::mult - 1){ plus(index, digit + 1, 1); plus(index, digit, oor - max()); } } template void nameTuple(IndexPack& iPack, Name& name) { std::get(iPack).name(name.get(N)); nameTuple(iPack, name); } template <> void nameTuple<0>(IndexPack& iPack, Name& name) { std::get<0>(iPack).name(name.get(0)); } } template MultiIndex& MultiIndex::operator++() { setPos( pos() + 1 ); plus(*this, 0, 1); return *this; } template MultiIndex& MultiIndex::operator--() { setPos( pos() - 1 ); plus(*this, 0, -1); return *this; } template MultiIndex& MultiIndex::operator+=(int n) { setPos( pos() + n ); plus(*this, 0, n); return *this; } template MultiIndex& MultiIndex::operator-=(int n) { setPos( pos() - n ); plus(*this, 0, 0-n); return *this; } template size_t MultiIndex::evaluate(const MultiIndex& in) const { return evaluate_x(in); } template void MultiIndex::name(const Name& nm) { name(nm.own()); if(nm.size() >= sizeof...(Indices)){ nameTuple(mIPack, nm); } else { Name nm2 = nm; nm2.autoName(sizeof...(Indices)); nameTuple(mIPack, nm); } } template size_t MultiIndex::dim() const { size_t res = 1; for(size_t i = 0; i != sMult; ++i){ res *= getIndex(i).dim(); } return res; } template bool MultiIndex::link(IndefinitIndexBase* toLink) { if(toLink->rangeType() != rangeType() and toLink->name() == name()){ // throw !! } if(toLink->rangeType() == rangeType() and toLink->name() == name()){ if(mLinked == toLink){ return true; // dont link twice the same } else if(mLinked == nullptr){ mLinked = toLink; return true; } else { return mLinked->link(toLink); } } else { return linkLower(toLink); } } template auto& MultiIndex::getIndex() -> decltype(std::get(mIPack)) { return std::get(mIPack); } template const auto& MultiIndex::getIndex() const -> decltype(std::get(mIPack)); { return std::get(mIPack); } template IndefinitIndexBase& MultiIndex::getIndex(size_t n) { if(n >= sMult){ // throw !! } MultiIndex* t = this; return getIndex(*t, n); } template const IndefinitIndexBase& MultiIndex::getIndex(size_t n) const { if(n >= sMult){ // throw !! } MultiIndex* t = this; return getIndex(*t, n); } template bool MultiIndex::linkLower(IndefinitIndexBase* toLink) { bool res = false; for(size_t i = 0; i != sMult; ++i){ res |= getIndex(i).link(toLink); } return res; } template void MultiIndex::linkTo(IndefinitIndexBase* target) { target->link(this); for(size_t i = 0; i != sMult; ++i){ getIndex(i).linkTo(target); } } /****************** * MultiRange * ******************/ template auto MultiRange::get() -> decltype( std::get(mSpace) ) { return std::get(mSpace); } }