#include "multi_range.h" namespace MultiArrayTools { /******************* * MultiIndexBase * *******************/ namespace { template struct IndexGetter { template static IndefinitIndexBase& getIndex(MultiIndex& in, size_t n) { if(n == N){ return in.getIndex(); } else { return IndexGetter::getIndex(in, n); } } template static const IndefinitIndexBase& getIndex(const MultiIndex& in, size_t n) { if(n == N){ return in.getIndex(); } else { return IndexGetter::getIndex(in, n); } } }; template <> struct IndexGetter<0> { template static IndefinitIndexBase& getIndex(MultiIndex& in, size_t n) { return in.getIndex<0>(); } template static const IndefinitIndexBase& getIndex(const MultiIndex& in, size_t n) { return in.getIndex<0>(); } }; template struct Evaluation { template static size_t evaluate(const MultiIndex& index) { const auto& subIndex = index.template getIndex(); return Evaluation::evaluate(index) * subIndex.max() + subIndex.pos(); } }; template <> struct Evaluation<0> { template static size_t evaluate(const MultiIndex& index) { const auto& subIndex = index.template getIndex<0>(); return subIndex.pos(); } }; template inline void plus(MultiIndex& index, size_t digit, int num) { IndefinitIndexBase& si = index.get(digit); si.setPos( si.pos() + num ); size_t oor = si.outOfRange(); if(oor and digit != 0){ plus(index, digit - 1, 1); plus(index, digit, -si.max()); } } template struct TupleNamer { template static void nameTuple(IndexPack& iPack, Name& name) { std::get(iPack).name(name.get(N)); TupleNamer::nameTuple(iPack, name); } }; template <> struct TupleNamer<0> { template static void nameTuple(IndexPack& iPack, Name& name) { std::get<0>(iPack).name(name.get(0)); } }; template struct IndexSubOrder { template static void subOrd(IndexPack& iPack, IndefinitIndexBase* major) { std::get(iPack).subOrd(major); IndexSubOrder::subOrd(iPack, major); } }; template <> struct IndexSubOrder<0> { template static void subOrd(IndexPack& iPack, IndefinitIndexBase* major) { std::get<0>(iPack).subOrd(major); } }; template struct PositionCopy { template static void copyPos(MultiIndex& target, const MultiIndex& source) { target.template getIndex().copyPos( source.template getIndex() ); PositionCopy::copyPos(target, source); } }; template <> struct PositionCopy<0> { template static void copyPos(MultiIndex& target, const MultiIndex& source) { target.template getIndex<0>().copyPos( source.template getIndex<0>() ); } }; template struct TupleSize { template static size_t getSize(const RangeTuple& rt) { return std::get(rt).size() * TupleSize::getSize(rt); } }; template <> struct TupleSize<0> { template static size_t getSize(const RangeTuple& rt) { return std::get<0>(rt).size(); } }; template struct IndexSetter { template static void setBegin(std::tuple& i, const std::tuple& r) { std::get(i) = std::get(r).begin(); IndexSetter::setBegin(i,r); } template static void setEnd(std::tuple& i, const std::tuple& r) { std::get(i) = std::get(r).end(); std::get(i) -= 1; IndexSetter::setEnd(i,r); } }; template <> struct IndexSetter<0> { template static void setBegin(std::tuple& i, const std::tuple& r) { std::get<0>(i) = std::get<0>(r).begin(); } template static void setEnd(std::tuple& i, const std::tuple& r) { std::get<0>(i) = std::get<0>(r).end(); std::get<0>(i) -= 1; } }; template struct RangeVecBuilder { template static void buildRangeVec(std::vector& rvec, const std::tuple& rs) { rvec.push_back(std::get(rs).type()); RangeVecBuilder::buildRangeVec(rvec, rs); } }; template <> struct RangeVecBuilder<0> { template static void buildRangeVec(std::vector& rvec, const std::tuple& rs) { rvec.push_back(std::get(rs).type()); } }; } template MultiIndex::MultiIndex(const MultiIndex& in) : IndexBase >(in), mIPack(in.mIPack) { // THAT's the point: IndexSubOrder::subOrd(mIPack, this); IIB::mPos = evaluate(*this); } template MultiIndex& MultiIndex::operator=(const MultiIndex& in) { IndexBase >::operator=(in); mIPack = in.mIPack; // THAT's the point: IndexSubOrder::subOrd(mIPack, this); IIB::mPos = evaluate(*this); return *this; } template MultiIndex::MultiIndex(RangeBase > const* range) : IndexBase >(range), mIPack() { operator=(IB::mRange->begin()); IIB::mPos = evaluate(*this); } template MultiIndex::MultiIndex(RangeBase > const* range, Indices&&... inds) : IndexBase >(range), mIPack(std::make_tuple(inds...)) { IndexSubOrder::subOrd(mIPack, this); IIB::mPos = evaluate(*this); } template MultiIndex::MultiIndex(RangeBase > const* range, const IndexPack& ipack) : IndexBase >(range), mIPack(ipack) { IndexSubOrder::subOrd(mIPack, this); IIB::mPos = evaluate(*this); } /* template MultiIndex::~MultiIndex() { IndexSubOrder::subOrd(mIPack, nullptr); }*/ template MultiIndex& MultiIndex::operator++() { plus(*this, sizeof...(Indices)-1, 1); IIB::setPos( evaluate(*this) ); return *this; } template MultiIndex& MultiIndex::operator--() { IIB::setPos( IIB::pos() - 1 ); plus(*this, 0, -1); return *this; } template MultiIndex& MultiIndex::operator+=(int n) { plus(*this, sizeof...(Indices)-1, 1); IIB::setPos( evaluate(*this) ); return *this; } template MultiIndex& MultiIndex::operator-=(int n) { IIB::setPos( IIB::pos() - n ); plus(*this, 0, 0-n); return *this; } template bool MultiIndex::operator==(const MultiIndex& in) { return IB::mRange == in.mRange and IIB::pos() == in.pos(); } template bool MultiIndex::operator!=(const MultiIndex& in) { return IB::mRange != in.mRange or IIB::pos() != in.pos(); } template IndefinitIndexBase& MultiIndex::operator=(size_t pos) { IIB::setPos( pos ); //setIndexPack(mIPack, pos); // -> implement !!! return *this; } template MultiRangeType MultiIndex::rangeType() const { return IB::mRange->type(); } template size_t MultiIndex::evaluate(const MultiIndex& in) const { size_t res = Evaluation::evaluate(in); return res; } template void MultiIndex::name(const Name& nm) { IIB::mName = nm.own(); if(nm.size() >= sizeof...(Indices)){ TupleNamer::nameTuple(mIPack, nm); } else { Name nm2 = nm; nm2.autoName(sizeof...(Indices)); TupleNamer::nameTuple(mIPack, nm2); } } template MultiIndex& MultiIndex::operator()(Indices&&... inds) { mIPack = std::make_tuple(inds...); IndexSubOrder::subOrd(mIPack, this); IIB::mPos = evaluate(*this); return *this; } template MultiIndex& MultiIndex::operator()(const Indices&... inds) { mIPack = std::make_tuple(Indices(inds)...); IndexSubOrder::subOrd(mIPack, this); IIB::mPos = evaluate(*this); return *this; } template size_t MultiIndex::dim() const { size_t res = 1; for(size_t i = 0; i != sizeof...(Indices); ++i){ res *= get(i).dim(); } return res; } template bool MultiIndex::link(IndefinitIndexBase* toLink) { if(toLink->rangeType() != rangeType() and toLink->name() == IIB::name() and not (IIB::name() == "master")){ // throw !! assert(0); } if(toLink->rangeType() == rangeType() and toLink->name() == IIB::name()){ if(IIB::mLinked == toLink or IIB::mSoftLinked == toLink){ return true; // dont link twice the same } else if(IIB::mLinked == nullptr and IIB::mSoftLinked == nullptr){ IIB::mLinked = toLink; return true; } else { if(IIB::mLinked == nullptr){ return IIB::mSoftLinked->link(toLink); } else { return IIB::mLinked->link(toLink); } } } else { if(linkLower(toLink)){ IIB::mSoftLinked = IIB::mLinked; IIB::mLinked = nullptr; return true; } else { return false; } } } template template typename std::tuple_element >::type& MultiIndex::getIndex() { return std::get(mIPack); } template template typename std::tuple_element >::type const& MultiIndex::getIndex() const { return std::get(mIPack); } template IndefinitIndexBase& MultiIndex::get(size_t n) { if(n >= sizeof...(Indices)){ // throw !! } MultiIndex* t = this; return IndexGetter::getIndex(*t, n); } template const IndefinitIndexBase& MultiIndex::get(size_t n) const { if(n >= sizeof...(Indices)){ // throw !! } MultiIndex const* t = this; return IndexGetter::getIndex(*t, n); } template bool MultiIndex::linkLower(IndefinitIndexBase* toLink) { bool res = false; for(size_t i = 0; i != sizeof...(Indices); ++i){ res |= get(i).link(toLink); } return res; } template void MultiIndex::linkTo(IndefinitIndexBase* target) { target->link(this); for(size_t i = 0; i != sizeof...(Indices); ++i){ get(i).linkTo(target); } } template void MultiIndex::copyPos(const MultiIndex& in) { PositionCopy::copyPos(*this, in); } template void MultiIndex::eval() { IIB::setPos( evaluate( *this ) ); } /* template struct RangeAssigner { template static void assignRange(const RangeBase >& multiRange, MultiIndex& multiIndex) { multiIndex.template getIndex().assignRange(nullptr &multiRange.template getRange()); RangeAssigner::assignRange(multiRange, multiIndex); } }; template <> struct RangeAssigner<0> { template static void assignRange(const RangeBase >& multiRange, MultiIndex& multiIndex) { multiIndex.template getIndex<0>().assignRange(nullptr &multiRange.template getRange<0>()); } }; template void MultiIndex::assignRange(RangeBase > const* range) { if(IB::toNull()){ IB::mRange = range; } MultiIndex& thisRef = *this; RangeAssigner::assignRange(*range, thisRef); }*/ /****************** * MultiRange * ******************/ template MultiRange::MultiRange(const Ranges&... rs) : mSpace(std::make_tuple(rs...)) {} template template auto MultiRange::getRange() -> decltype( std::get(MultiRange::SpaceType()) ) { return std::get(mSpace); } template template auto MultiRange::getRange() const -> decltype( std::get(MultiRange::SpaceType()) ) { return std::get(mSpace); } template size_t MultiRange::size() const { return TupleSize::getSize(mSpace); } template MultiRangeType MultiRange::type() const { std::vector rvec; RangeVecBuilder::buildRangeVec(rvec, mSpace); return MultiRangeType(rvec); } template const typename MultiRange::SpaceType& MultiRange::space() const { return mSpace; } template MultiIndex MultiRange::begin() const { std::tuple is; IndexSetter::setBegin(is,mSpace); return MultiIndex(this, is); } template MultiIndex MultiRange::end() const { std::tuple is; IndexSetter::setEnd(is,mSpace); return ++MultiIndex(this, is); } }