diff --git a/src/base_def.h b/src/base_def.h index 67fb75f..1aefc47 100644 --- a/src/base_def.h +++ b/src/base_def.h @@ -105,7 +105,7 @@ namespace MultiArrayTools // container_range.h template class ContainerIndex; - + // multi_array.h template class MultiArrayBase; @@ -118,6 +118,42 @@ namespace MultiArrayTools template class MultiArray; + // block.h + template + class BlockBase; + + // block.h + template + class MutableBlockBase; + + // block.h + template + class Block; + + // block.h + template + class MBlock; + + // block.h + template + class BlockValue; + + // block.h + template + class MBlockValue; + + // block.h + template + class SplitBlock; + + // block.h + template + class MSplitBlock; + + // block.h + template + class BlockResult; + // multi_array_operation.h template class OperationBase; diff --git a/src/block.cc b/src/block.cc index 03d045e..0eb0b52 100644 --- a/src/block.cc +++ b/src/block.cc @@ -54,6 +54,13 @@ namespace MultiArrayHelper { return operate >(in); } + + /************************ + * MutableBlockBase * + ************************/ + + template + MutableBlockBase::MutableBlockBase(size_t size) : BlockBase(size) {} /************* * Block * @@ -83,6 +90,41 @@ namespace MultiArrayHelper mBegPtr = nbeg; return *this; } + + /************** + * MBlock * + **************/ + + template + MBlock::MBlock(const std::vector& data, + size_t begPos, size_t size) : + MutableBlockBase(size), + mBegPtr(data.data() + begPos) {} + + template + BlockType MBlock::type() const + { + return BlockType::BLOCK; + } + + template + const T& MBlock::operator[](size_t i) const + { + return *(mBegPtr + i); + } + + template + T& MBlock::operator[](size_t i) + { + return *(mBegPtr + i); + } + + template + MBlock& MBlock::set(const T* nbeg) + { + mBegPtr = nbeg; + return *this; + } /****************** * BlockValue * @@ -112,6 +154,40 @@ namespace MultiArrayHelper return *this; } + /******************* + * MBlockValue * + *******************/ + + template + MBlockValue::MBlockValue(const T& val, size_t size) : + BlockBase(size), + mVal(val) {} + + template + BlockType MBlockValue::type() const + { + return BlockType::VALUE; + } + + template + const T& MBlockValue::operator[](size_t i) const + { + return mVal; + } + + template + T& MBlockValue::operator[](size_t i) + { + return mVal; + } + + template + MBlockValue& MBlockValue::set(const T* nbeg) + { + mVal = *nbeg; + return *this; + } + /****************** * SplitBlock * ******************/ @@ -141,6 +217,42 @@ namespace MultiArrayHelper mBegPtr = nbeg; return *this; } + + /******************* + * MSplitBlock * + *******************/ + + template + MSplitBlock::MSplitBlock(const std::vector& data, size_t begPos, + size_t stepSize, size_t size) : + BlockBase(size), + mStepSize(stepSize), + mBegPtr(data.data() + begPos) {} + + template + BlockType MSplitBlock::type() const + { + return BlockType::SPLIT; + } + + template + const T& MSplitBlock::operator[](size_t pos) const + { + return *(mBegPtr + pos*mStepSize); + } + + template + T& MSplitBlock::operator[](size_t pos) + { + return *(mBegPtr + pos*mStepSize); + } + + template + MSplitBlock& MSplitBlock::set(const T* nbeg) + { + mBegPtr = nbeg; + return *this; + } /******************* * BlockResult * diff --git a/src/block.h b/src/block.h index df7a324..e5d13a0 100644 --- a/src/block.h +++ b/src/block.h @@ -47,6 +47,18 @@ namespace MultiArrayHelper size_t mSize; }; + template + class MutableBlockBase : public BlockBase + { + public: + + MutableBlockBase() = default; + MutableBlockBase(size_t size); + + virtual T& operator[](size_t pos) override; + + }; + template class Block : public BlockBase { @@ -62,6 +74,22 @@ namespace MultiArrayHelper const T* mBegPtr; }; + template + class MBlock : public MutableBlockBase + { + public: + MBlock() = default; + MBlock(std::vector& data, size_t begPos, size_t size); + + virtual BlockType type() const override; + virtual const T& operator[](size_t pos) const override; + virtual T& operator[](size_t pos) override; + virtual Block& set(const T* nbeg) override; + + protected: + T* mBegPtr; + }; + template class BlockValue : public BlockBase { @@ -77,7 +105,22 @@ namespace MultiArrayHelper T mVal; }; - + template + class MBlockValue : public MutableBlockBase + { + public: + MBlockValue() = default; + MBlockValue(T& val, size_t size); + + virtual BlockType type() const override; + virtual const T& operator[](size_t pos) const override; + virtual T& operator[](size_t pos) override; + virtual BlockValue& set(const T* nbeg) override; + + protected: + T& mVal; + }; + template class SplitBlock : public BlockBase { @@ -97,7 +140,27 @@ namespace MultiArrayHelper }; template - class BlockResult : public BlockBase + class MSplitBlock : public MutableBlockBase + { + public: + + MSplitBlock() = default; + MSplitBlock(std::vector& data, size_t begPos, + size_t stepSize, size_t size); + + virtual BlockType type() const override; + virtual const T& operator[](size_t pos) const override; + virtual T& operator[](size_t pos) override; + virtual SplitBlock& set(const T* nbeg) override; + + protected: + size_t mStepSize; + T* mBegPtr; + }; + + + template + class BlockResult : public MutableBlockBase { public: BlockResult() = default; @@ -105,7 +168,7 @@ namespace MultiArrayHelper virtual BlockType type() const override; virtual const T& operator[](size_t pos) const override; - virtual T& operator[](size_t i); + virtual T& operator[](size_t i) override; virtual BlockResult& set(const T* nbeg) override; protected: diff --git a/src/container_range.cc b/src/container_range.cc index d499261..ac0698f 100644 --- a/src/container_range.cc +++ b/src/container_range.cc @@ -78,6 +78,22 @@ namespace MultiArrayTools return *this; } + template + size_t ContainerIndex::pp(std::shared_ptr& idxPtr) + { + size_t tmp = pp(mIPack, mBlockSizes, idxPtr); + IB::mPos += tmp; + return tmp; + } + + template + size_t ContainerIndex::mm(std::shared_ptr& idxPtr) + { + size_t tmp = mm(mIPack, mBlockSizes, idxPtr); + IB::mPos -= tmp; + return tmp; + } + template typename ContainerIndex::MetaType ContainerIndex::meta() const { diff --git a/src/container_range.h b/src/container_range.h index edbb796..c5bc32a 100644 --- a/src/container_range.h +++ b/src/container_range.h @@ -44,6 +44,9 @@ namespace MultiArrayTools virtual ContainerIndex& operator--() override; virtual ContainerIndex& operator=(size_t pos) override; + virtual size_t pp(std::shared_ptr& idxPtr) override; + virtual size_t mm(std::shared_ptr& idxPtr) override; + virtual MetaType meta() const override; virtual ContainerIndex& at(const MetaType& metaPos) override; diff --git a/src/index_base.cc b/src/index_base.cc index 352cc52..545d0b5 100644 --- a/src/index_base.cc +++ b/src/index_base.cc @@ -33,7 +33,7 @@ namespace MultiArrayTools { return mRangePtr->size(); } - + /* bool IndexBase::locked() const { return mLocked; @@ -44,7 +44,7 @@ namespace MultiArrayTools mLocked = (idx.get() == this); return *this; } - + */ IndexBase::operator size_t() const { diff --git a/src/index_base.h b/src/index_base.h index 27a40ac..f84a47c 100644 --- a/src/index_base.h +++ b/src/index_base.h @@ -43,6 +43,9 @@ namespace MultiArrayTools virtual IndexBase& operator=(size_t pos) = 0; virtual IndexBase& operator++() = 0; virtual IndexBase& operator--() = 0; + + virtual size_t pp(std::shared_ptr& idxPtr) = 0; + virtual size_t mm(std::shared_ptr& idxPtr) = 0; bool operator==(const IndexBase& in) const; bool operator!=(const IndexBase& in) const; @@ -53,9 +56,9 @@ namespace MultiArrayTools virtual bool last() const = 0; virtual bool first() const = 0; - - virtual bool locked() const; - virtual IndexBase& lock(std::shared_ptr& idx); + + //virtual bool locked() const; + //virtual IndexBase& lock(std::shared_ptr& idx); virtual std::shared_ptr getPtr(size_t n) const = 0; @@ -67,7 +70,7 @@ namespace MultiArrayTools std::shared_ptr mRangePtr; size_t mPos; size_t mId; - bool mLocked = false; + //bool mLocked = false; }; template diff --git a/src/multi_array_operation.cc b/src/multi_array_operation.cc index 0589bb7..973990d 100644 --- a/src/multi_array_operation.cc +++ b/src/multi_array_operation.cc @@ -19,31 +19,66 @@ namespace MultiArrayTools ivec.push_back(ii); } } - - BlockType getBlockType(std::shared_ptr i, - std::shared_ptr j, bool first) + + // !!! + BTSS getBlockType(std::shared_ptr i, + std::shared_ptr j, bool first) { - BlockType out = BlockType::VALUE; + // returning BlockType and step size is redundant (change in the future) + // stepSize == 0 => VALUE + // stepSize == 1 => BLOCK + // stepSize > 1 => SPLIT :) + BTSS out(BlockType::VALUE, 0); for(size_t inum = 0; inum != i->range()->dim(); ++inum){ + auto ii = i->getPtr(inum); if(ii == j){ - if(inum == 0){ - out = BlockType::BLOCK; + if(inum == 0 and first){ + out = BTSS(BlockType::BLOCK, 1); } else { - out = BlockType::SPLIT; + out = BTSS(BlockType::SPLIT, i->getStepSize(inum)); } continue; } - if(ii->type() == IndexType::MULTI){ - BlockType tmp = getBlockType(ii, j, ivec); - if(tmp != BlockType::VALUE){ + if(ii->type() == IndexType::MULTI or + ii->type() == IndexType::CONT){ + BTSS tmp = getBlockType(ii, j, inum == 0); + if(tmp.first != BlockType::VALUE){ out = tmp; } } } return out; } + + template + std::shared_ptr > makeBlock(const std::vector& vec, size_t stepSize, size_t blockSize) + { + if(stepSize == 0){ + return std::make_shared >(vec[0], blockSize); + } + else if(stepSize == 1){ + return std::make_shared >(vec, 0, blockSize); + } + else { + return std::make_shared >(vec, 0, stepSize, blockSize); + } + } + + template + std::shared_ptr > makeBlock(std::vector& vec, size_t stepSize, size_t blockSize) + { + if(stepSize == 0){ + return std::make_shared >(vec[0], blockSize); + } + else if(stepSize == 1){ + return std::make_shared >(vec, 0, blockSize); + } + else { + return std::make_shared >(vec, 0, stepSize, blockSize); + } + } /********************************* * MultiArrayOperationBase * @@ -106,9 +141,11 @@ namespace MultiArrayTools std::dynamic_pointer_cast >( mrf.create() ); mIndex = std::make_shared( mr->begin() ); (*mIndex) = *index; - // -> find optimal block index !!! - // -> lock this index !!! - for(*mIndex = 0; mIndex->pos() != mIndex->max(); ++(*mIndex)){ + + auto blockIndex = seekBlockIndex(mIndex, second); + block(blockIndex); + second.block(blockIndex); + for(*mIndex = 0; mIndex->pos() != mIndex->max(); mIndex->pp(blockIndex) )){ get() = mSecond.get(); } } @@ -128,10 +165,11 @@ namespace MultiArrayTools } template - std::vector OperationMaster::block(const std::shared_ptr& blockIndex) const + std::vector OperationMaster::block(const std::shared_ptr& blockIndex) const { - // seek index with smallest number of SPLITs !!! - + std::vector btv(1, getBlockType(mIndex, blockIndex, true) ); + mBlockPtr = makeBlock(mArrayRef.data(), btv[0].second, blockIndex->max()); + return btv; } template @@ -163,9 +201,11 @@ namespace MultiArrayTools } template - std::vector ConstOperationRoot::block(const std::shared_ptr& blockIndex) const + std::vector ConstOperationRoot::block(const std::shared_ptr& blockIndex) const { - // !!! + std::vector btv(1, getBlockType(mIndex, blockIndex, true) ); + mBlockPtr = makeBlock(mArrayRef.data(), btv[0].second, blockIndex->max()); + return btv; } template @@ -206,13 +246,15 @@ namespace MultiArrayTools BlockBase& OperationRoot::get() { block(); - return *mBlockPtr; // issue: const !!! + return *mBlockPtr; } template - std::vector OperationRoot::block(const std::shared_ptr& blockIndex) const + std::vector OperationRoot::block(const std::shared_ptr& blockIndex) const { - // !!! + std::vector btv(1, getBlockType(mIndex, blockIndex, true) ); + mBlockPtr = makeBlock(mArrayRef.data(), btv[0].second, blockIndex->max()); + return btv; } template @@ -239,9 +281,11 @@ namespace MultiArrayTools } template - std::vector Operation::block(const std::shared_ptr& blockIndex) const + std::vector Operation::block(const std::shared_ptr& blockIndex) const { - // !!! + std::vector btv; + PackNum::makeBlockTypeVec(btv, mOps, blockIndex); + return btv; } template diff --git a/src/multi_array_operation.h b/src/multi_array_operation.h index 80d1830..6e6703e 100644 --- a/src/multi_array_operation.h +++ b/src/multi_array_operation.h @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "base_def.h" @@ -32,9 +34,73 @@ namespace MultiArrayTools void seekIndexInst(std::shared_ptr i, std::vector >& ivec); - BlockType getBlockType(std::shared_ptr i, - std::shared_ptr j, bool first); + + // + typedef std::pair BTSS; + + BTSS getBlockType(std::shared_ptr i, + std::shared_ptr j, bool first); + template + std::shared_ptr > makeBlock(const std::vector& vec, size_t stepSize, size_t blockSize); + + template + std::shared_ptr > makeBlock(std::vector& vec, size_t stepSize, size_t blockSize); + + size_t getBTNum(const std::vector& mp, BlockType bt) + { + size_t out = 0; + for(auto& xx: mp){ + if(xx.first == bt){ + ++out; + } + } + return out; + } + + void minimizeAppearanceOfType(std::map, std::vector > mp, + BlockType bt) + { + size_t minNum = getBTNum( *mp.begin(), bt ); + for(auto& mm: mp){ + size_t tmp = getBTNum( mm.second, bt ); + if(tmp < minNum){ + minNum = tmp; + } + } + + for(auto mit = mp.begin(); mit != mp.end(); ){ + size_t tmp = getBTNum( mit->second, bt ); + if(tmp > minNum){ + mit = mp.erase(mit); + } + else { + ++mit; + } + } + + } + + template + std::shared_ptr seekBlockIndex(std::shared_ptr& ownIdx, + const OperationBase& second) + { + std::vector > ivec; + seekIndexInst(ownIdx, ivec); + std::map, std::vector > mp; + + for(auto& xx: ivec){ + mp[xx] = second.block(xx); + } + + // seek minimal number of VALUEs => guarantees absence of conflicting blocks + minimizeAppearanceOfType(mp, BlockType::VALUE); + + // seek mininmal number of SPLITs => maximal vectorization possible + minimizeAppearanceOfType(mp, BlockType::SPLIT); + + return *mp.begin(); + } template class OperationBase @@ -52,9 +118,6 @@ namespace MultiArrayTools //virtual size_t argNum() const = 0; virtual const BlockBase& get() const = 0; - - protected: - mutable std::shared_ptr mBlockPtr; }; template @@ -109,7 +172,7 @@ namespace MultiArrayTools OperationMaster(MutableMultiArrayBase& ma, const OperationBase& second, std::shared_ptr& index); - virtual BlockBase& get() override; + virtual MutableBlockBase& get() override; virtual const BlockBase& get() const override; virtual std::vector block(const std::shared_ptr& blockIndex) const override; @@ -121,7 +184,7 @@ namespace MultiArrayTools OperationBase const& mSecond; MutableMultiArrayBase& mArrayRef; std::shared_ptr mIndex; - + mutable std::shared_ptr mBlockPtr; }; @@ -149,6 +212,7 @@ namespace MultiArrayTools MultiArrayBase const& mArrayRef; std::shared_ptr mIndex; + mutable std::shared_ptr mBlockPtr; }; template @@ -169,7 +233,7 @@ namespace MultiArrayTools OperationMaster operator=(const OperationBase& in); virtual const BlockBase& get() const override; - virtual BlockBase& get() override; + virtual MutableBlockBase& get() override; virtual std::vector block(const std::shared_ptr& blockIndex) const override; virtual OperationRoot& block() const override; @@ -178,6 +242,7 @@ namespace MultiArrayTools MutableMultiArrayBase& mArrayRef; std::shared_ptr mIndex; + mutable std::shared_ptr mBlockPtr; }; template diff --git a/src/multi_range.cc b/src/multi_range.cc index 71ee330..ef7f994 100644 --- a/src/multi_range.cc +++ b/src/multi_range.cc @@ -59,15 +59,16 @@ namespace MultiArrayTools template MultiIndex& MultiIndex::operator++() { - // return step size -> add to IB::mPos - IB::mPos += PackNum::pp( mIPack, mBlockSizes ); + PackNum::pp( mIPack ); + ++IB::mPos; return *this; } template MultiIndex& MultiIndex::operator--() { - IB::mPos -= PackNum::mm( mIPack, mBlockSizes ); + PackNum::mm( mIPack ); + --IB::mPos; return *this; } @@ -79,13 +80,29 @@ namespace MultiArrayTools return *this; } + template + size_t MultiIndex::pp(std::shared_ptr& idxPtr) + { + size_t tmp = pp(mIPack, mBlockSizes, idxPtr); + IB::mPos += tmp; + return tmp; + } + + template + size_t MultiIndex::mm(std::shared_ptr& idxPtr) + { + size_t tmp = mm(mIPack, mBlockSizes, idxPtr); + IB::mPos -= tmp; + return tmp; + } + template template MultiIndex& MultiIndex::up() { static_assert(DIR < sizeof...(Indices), "DIR exceeds number of sub-indices"); IB::mPos += PackNum::blockSize( mIPack ); - PackNum::pp( mIPack ); + PackNum::pp( mIPack ); return *this; } @@ -95,7 +112,7 @@ namespace MultiArrayTools { static_assert(DIR < sizeof...(Indices), "DIR exceeds number of sub-indices"); IB::mPos -= PackNum::blockSize( mIPack ); - PackNum::mm( mIPack ); + PackNum::mm( mIPack ); return *this; } @@ -141,6 +158,15 @@ namespace MultiArrayTools return PackNum::getIndexPtr(*t, n); } + size_t getStepSize(size_t n) const + { + if(n >= sizeof...(Indices)){ + assert(0); + // throw !! + } + return mBlockSizes[n+1]; + } + template typename MultiIndex::MetaType MultiIndex::meta() const { @@ -174,14 +200,14 @@ namespace MultiArrayTools { return std::dynamic_pointer_cast( IB::mRangePtr ); } - + /* template MultiIndex& MultiIndex::lock(std::shared_ptr& idx) { IB::mLocked = (idx.get() == this); PackNum::lock(mIPack, idx); return *this; - } + }*/ template MultiIndex& MultiIndex::operator()(std::shared_ptr&... indices) diff --git a/src/multi_range.h b/src/multi_range.h index 61c507e..7783966 100644 --- a/src/multi_range.h +++ b/src/multi_range.h @@ -46,6 +46,9 @@ namespace MultiArrayTools virtual MultiIndex& operator--() override; virtual MultiIndex& operator=(size_t pos) override; + virtual size_t pp(std::shared_ptr& idxPtr) override; + virtual size_t mm(std::shared_ptr& idxPtr) override; + template MultiIndex& up(); @@ -60,6 +63,7 @@ namespace MultiArrayTools const IndexBase& get(size_t n) const; virtual std::shared_ptr getPtr(size_t n) const override; + virtual size_t getStepSize(size_t n) const override; virtual MetaType meta() const override; virtual MultiIndex& at(const MetaType& metaPos) override; @@ -71,7 +75,7 @@ namespace MultiArrayTools std::shared_ptr range() const; - virtual MultiIndex& lock(std::shared_ptr& idx) override; + //virtual MultiIndex& lock(std::shared_ptr& idx) override; // raplace instances (in contrast to its analogon in ContainerIndex // MultiIndices CANNOT be influences be its subindices, so there is diff --git a/src/pack_num.h b/src/pack_num.h index 6348cf7..63d6018 100644 --- a/src/pack_num.h +++ b/src/pack_num.h @@ -62,7 +62,7 @@ namespace MultiArrayHelper static void initBlockSizes(std::array& bs, std::tuple...>& ip) { - if(N == sizeof...(Indices)){ + if(N == sizeof...(Indices)+1){ std::get(bs) = 1; } else { @@ -72,42 +72,67 @@ namespace MultiArrayHelper } template - static inline size_t pp(std::tuple...>& ip, - std::array& bs) + static inline void pp(std::tuple...>& ip) { auto& si = *std::get(ip); - if(si.last() or si.locked()){ + if(si.last()){ si = 0; PackNum::pp(ip); } else { ++si; } - if(si.locked()){ - return std::get(bs) - std::get(bs) + 1; - } - else { - return 1; - } } template - static inline size_t mm(std::tuple...>& ip, - std::array& bs) + static inline size_t pp(std::tuple...>& ip, + std::array& bs, + std::shared_ptr& idxPtr) + { + auto siPtr = std::get(ip); + if(siPtr.get() == idxPtr.get()){ + return std::get(bs) + PackNum::pp(ip); + } + else { + if(siPtr->last()){ + (*siPtr) = 0; + return PackNum::pp(ip, bs) - siPtr->max() + 1; + } + else { + return siPtr->pp(idxPtr); + } + } + } + + template + static inline void mm(std::tuple...>& ip) { auto& si = *std::get(ip); - if(si.first() or si.locked()){ + if(si.first()){ si = si.max(); PackNum::mm(ip); } else { --si; } - if(si.locked()){ - return std::get(bs) - std::get(bs) + 1; + } + + template + static inline size_t mm(std::tuple...>& ip, + std::array& bs, + std::shared_ptr& idx) + { + auto siPtr = std::get(ip); + if(siPtr.get() == idxPtr.get()){ + return std::get(bs) + PackNum::mm(ip); } else { - return 1; + if(siPtr->first()){ + return PackNum::mm(ip, bs) - siPtr->max() + 1; + } + else { + return siPtr->pp(idx); + } } } @@ -200,6 +225,16 @@ namespace MultiArrayHelper { return PackNum::template unpackArgs(tp, std::get(tp).get(), args...); } + + template + static void makeBlockTypeVec(std::vector >& btv, + const std::tuple& ops, + std::shared_ptr& idxPtr) + { + auto& subvec = std::get(ops).block(idxPtr); + btv.insert(btv.end(), subvec.begin(), subvec.end() ); + PackNum::makeBlockTypeVec(btv, ops, idxPtr); + } }; @@ -237,6 +272,13 @@ namespace MultiArrayHelper { std::get<0>(bs) = PackNum::blockSize(ip); } + + template + static inline void pp(std::tuple...>& ip) + { + auto& si = *std::get<0>(ip); + ++si; + } template static inline size_t pp(std::tuple...>& ip, @@ -252,6 +294,13 @@ namespace MultiArrayHelper return 1; } } + + template + static inline size_t mm(std::tuple...>& ip) + { + auto& si = *std::get<0>(ip); + --si; + } template static inline size_t mm(std::tuple...>& ip, @@ -353,6 +402,15 @@ namespace MultiArrayHelper return f(std::get<0>(tp).get(), args...); } + template + static void makeBlockTypeVec(std::vector >& btv, + const std::tuple& ops, + std::shared_ptr& idxPtr) + { + auto& subvec = std::get<0>(ops).block(idxPtr); + btv.insert(btv.end(), subvec.begin(), subvec.end() ); + } + }; } // end namespace MultiArrayHelper diff --git a/src/single_range.cc b/src/single_range.cc index c494cdc..a230918 100644 --- a/src/single_range.cc +++ b/src/single_range.cc @@ -38,6 +38,20 @@ namespace MultiArrayTools return *this; } + template + size_t SingleIndex::pp(std::shared_ptr& idxPtr) + { + ++(*this); + return 1; + } + + template + size_t SingleIndex::mm(std::shared_ptr& idxPtr) + { + --(*this); + return 1; + } + template U SingleIndex::meta() const { diff --git a/src/single_range.h b/src/single_range.h index 4ad8b44..e481668 100644 --- a/src/single_range.h +++ b/src/single_range.h @@ -33,6 +33,9 @@ namespace MultiArrayTools virtual SingleIndex& operator++() override; virtual SingleIndex& operator--() override; + virtual size_t pp(std::shared_ptr& idxPtr) override; + virtual size_t mm(std::shared_ptr& idxPtr) override; + virtual U meta() const override; virtual SingleIndex& at(const U& metaPos) override;