// -*- C++ -*- #ifndef __multi_range_h__ #define __multi_range_h__ #include #include #include #include #include "ranges/range_base.h" #include "ranges/index_base.h" #include "ranges/range_helper.h" #include "ranges/multi_range_factory_product_map.h" #include "ranges/x_to_string.h" #include "ranges/type_map.h" #include "statics/static_for.h" namespace CNORXZ { namespace { using namespace CNORXZInternal; } template class MultiIndex : public IndexInterface, std::tuple > { public: typedef IndexInterface, std::tuple > IB; typedef std::tuple...> IndexPack; typedef std::tuple MetaType; typedef MultiRange RangeType; typedef MultiIndex IType; static constexpr IndexType sType() { return IndexType::MULTI; } static constexpr size_t sDim() { return sizeof...(Indices); } static constexpr size_t totalDim() { return (... * Indices::totalDim()); } static constexpr SpaceType STYPE = SpaceType::ANY; static constexpr bool PARALLEL = std::tuple_element<0,std::tuple>::type::PARALLEL; private: IndexPack mIPack; std::array mBlockSizes; public: const IndexPack& pack() const { return mIPack; } MultiIndex() = delete; // NO DEFAULT HERE !!! // ( have to assign sub-indices (ptr!) correctly ) template MultiIndex(const std::shared_ptr& range); template MultiIndex& up(); template MultiIndex& down(); template auto get() const -> decltype( *std::get( mIPack ) )&; template auto getPtr() const -> decltype( std::get( mIPack ) )&; template size_t getBlockSize() const { return std::get(mBlockSizes); } // raplace instances (in contrast to its analogon in ConstContainerIndex // MultiIndices CANNOT be influences be its subindices, so there is // NO foreign/external controll) // Do NOT share index instances between two or more MultiIndex instances MultiIndex& operator()(std::shared_ptr&... indices); MultiIndex& operator()(const std::tuple...>& indices); // ==== >>>>> STATIC POLYMORPHISM <<<<< ==== IndexType type() const; MultiIndex& operator=(size_t pos); MultiIndex& operator++(); MultiIndex& operator--(); int pp(std::intptr_t idxPtrNum); int mm(std::intptr_t idxPtrNum); std::string stringMeta() const; MetaType meta() const; MultiIndex& at(const MetaType& metaPos); size_t dim(); bool first(); bool last(); std::shared_ptr range(); template auto getPtr() -> decltype( std::get( mIPack ) )&; size_t getStepSize(size_t n); template auto ifor(size_t step, Exprs exs) const; template auto iforh(size_t step, Exprs exs) const; template auto pifor(size_t step, Exprs exs) const; }; /************************* * MultiRangeFactory * *************************/ // NOT THREAD SAVE template class MultiRangeFactory : public RangeFactoryBase { public: typedef MultiRange oType; MultiRangeFactory() = delete; MultiRangeFactory(const std::shared_ptr&... rs); MultiRangeFactory(const typename MultiRange::Space& space); virtual std::shared_ptr create() override; private: std::shared_ptr checkIfCreated(const std::tuple...>& ptp); }; /****************** * MultiRange * ******************/ template class MultiRange : public RangeInterface > { public: typedef RangeBase RB; typedef std::tuple...> Space; typedef MultiIndex IndexType; typedef std::tuple MetaType; typedef MultiRange RangeType; typedef MultiRangeFactory FType; protected: MultiRange() = delete; MultiRange(const MultiRange& in) = delete; MultiRange& operator=(const MultiRange& in) = delete; MultiRange(const std::shared_ptr&... rs); MultiRange(const Space& space); Space mSpace; public: static const size_t sdim = sizeof...(Ranges); template auto get() const -> decltype( *std::get( mSpace ) )&; size_t getMeta(const MetaType& metaPos) const; template auto getPtr() const -> decltype( std::get( mSpace ) )&; virtual std::shared_ptr sub(size_t num) const override; virtual size_t dim() const final; virtual size_t size() const final; virtual SpaceType spaceType() const final; virtual DataHeader dataHeader() const final; virtual vector typeNum() const final; virtual size_t cmeta(char* target, size_t pos) const final; virtual size_t cmetaSize() const final; virtual std::string stringMeta(size_t pos) const final; virtual vector data() const final; const Space& space() const; virtual IndexType begin() const final; virtual IndexType end() const final; template auto cat(const std::shared_ptr >& erange) -> std::shared_ptr >; friend MultiRangeFactory; static constexpr bool HASMETACONT = false; static constexpr bool defaultable = false; static constexpr size_t ISSTATIC = (... & Ranges::ISSTATIC); static constexpr size_t SIZE = (... * Ranges::SIZE); }; } /* ========================= * * --- TEMPLATE CODE --- * * ========================= */ namespace CNORXZ { namespace { using namespace CNORXZInternal; } // -> define in range_base.cc std::shared_ptr mkMULTI(const char** dp); /****************** * MultiIndex * ******************/ template template MultiIndex::MultiIndex(const std::shared_ptr& range) : IndexInterface,std::tuple >(range, 0) { std::get(mBlockSizes) = 1; sfor_mn ( [&](auto i) { auto r = range->template getPtr(); std::get(mIPack) = r->beginPtr(); *std::get(mIPack) = 0; std::get(mBlockSizes) = sfor_p ( [&](auto j) { return std::get(mIPack)->max(); } , [&](auto a, auto b) { return a * b; }); return 0; }); IB::mPos = sfor_m ( [&](auto i) { return std::get(mIPack); }, [&](auto a, auto b) {return a->pos() + b*a->max();}, 0 ); } template template MultiIndex& MultiIndex::up() { static_assert(DIR < sizeof...(Indices), "DIR exceeds number of sub-indices"); IB::mPos += sfor_p ( [&](auto i) { return std::get(mIPack)->max(); }, [&](auto a, auto b) { return a * b; } ); sfor_m ( [&](auto i) { auto& si = *std::get( mIPack ); if(si.last() and i != 0) { si = 0; return true; } else { ++si; return false; } return false; } ); return *this; } template template MultiIndex& MultiIndex::down() { static_assert(DIR < sizeof...(Indices), "DIR exceeds number of sub-indices"); IB::mPos -= sfor_p ( [&](auto i) { return std::get(mIPack)->max(); }, [&](auto a, auto b) { return a * b; } ); sfor_m ( [&](auto i) { auto& si = *std::get( mIPack ); if(si.first() and i != 0) { si = si.max()-1; return true; } else { --si; return false; } return false; } ); return *this; } template template auto MultiIndex::get() const -> decltype( *std::get( mIPack ) )& { return *std::get(mIPack); } template template auto MultiIndex::getPtr() const -> decltype( std::get( mIPack ) )& { return std::get(mIPack); } template MultiIndex& MultiIndex::operator()(std::shared_ptr&... indices) { return (*this)(std::make_tuple(indices...)); } template MultiIndex& MultiIndex::operator()(const std::tuple...>& indices) { sfor_pn<0,sizeof...(Indices)> ( [&](auto i) { std::get(mIPack) = std::get(indices); return 0; } ); RangeHelper::setIndexPack(mIPack, IB::mPos); return *this; } template IndexType MultiIndex::type() const { return IndexType::MULTI; } template MultiIndex& MultiIndex::operator=(size_t pos) { IB::mPos = pos; RangeHelper::setIndexPack(mIPack, pos); return *this; } template MultiIndex& MultiIndex::operator++() { sfor_m ( [&](auto i) { auto& si = *std::get( mIPack ); if(si.last() and i != 0) { si = 0; return true; } else { ++si; return false; } return false; } ); ++IB::mPos; return *this; } template MultiIndex& MultiIndex::operator--() { sfor_m ( [&](auto i) { auto& si = *std::get( mIPack ); if(si.first() and i != 0) { si = si.max()-1; return true; } else { --si; return false; } return false; } ); --IB::mPos; return *this; } template int MultiIndex::pp(std::intptr_t idxPtrNum) { const int tmp = RangeHelper::ppx(mIPack, mBlockSizes, idxPtrNum); IB::mPos += tmp; return tmp; } template int MultiIndex::mm(std::intptr_t idxPtrNum) { const int tmp = RangeHelper::mmx(mIPack, mBlockSizes, idxPtrNum); IB::mPos -= tmp; return tmp; } template std::string MultiIndex::stringMeta() const { return std::dynamic_pointer_cast( IB::mRangePtr )->stringMeta(IB::mPos); } template typename MultiIndex::MetaType MultiIndex::meta() const { MetaType metaTuple; sfor_pn<0,sizeof...(Indices)> ( [&](auto i) { std::get(metaTuple) = std::get(mIPack)->meta(); return 0; } ); return metaTuple; } template MultiIndex& MultiIndex::at(const MetaType& metaPos) { sfor_pn<0,sizeof...(Indices)> ( [&](auto i) { std::get(mIPack)->at( std::get(metaPos) ); return 0; } ); IB::mPos = sfor_m ( [&](auto i) { return std::get(mIPack); }, [&](auto a, auto b) {return a->pos() + b*a->max();}, 0 ); return *this; } template size_t MultiIndex::dim() { return sizeof...(Indices); } template bool MultiIndex::first() { return IB::mPos == 0; } template bool MultiIndex::last() { return IB::mPos == IB::mMax - 1; } template std::shared_ptr::RangeType> MultiIndex::range() { return std::dynamic_pointer_cast( IB::mRangePtr ); } template template auto MultiIndex::getPtr() -> decltype( std::get( mIPack ) )& { return std::get(mIPack); } template size_t MultiIndex::getStepSize(size_t n) { if(n >= sizeof...(Indices)){ assert(0); // throw !! } return mBlockSizes[n+1]; } template template auto MultiIndex::ifor(size_t step, Exprs exs) const { return RangeHelper::mkFor<0>(step, mIPack, mBlockSizes, exs); } template template auto MultiIndex::iforh(size_t step, Exprs exs) const { return RangeHelper::mkForh<0>(step, mIPack, mBlockSizes, exs); } template template auto MultiIndex::pifor(size_t step, Exprs exs) const { return RangeHelper::mkPFor<0>(step, mIPack, mBlockSizes, exs); } /************************* * MultiRangeFactory * *************************/ template MultiRangeFactory::MultiRangeFactory(const std::shared_ptr&... rs) { mProd = std::shared_ptr< MultiRange >( new MultiRange( rs... ) ); } template MultiRangeFactory::MultiRangeFactory(const typename MultiRange::Space& st) { mProd = std::shared_ptr< MultiRange >( new MultiRange( st ) ); } template std::shared_ptr MultiRangeFactory::create() { mProd = checkIfCreated( std::dynamic_pointer_cast( mProd )->mSpace ); setSelf(); return mProd; } template std::shared_ptr MultiRangeFactory::checkIfCreated(const std::tuple...>& ptp) { std::shared_ptr out; bool check = false; for(auto& x: MultiRangeFactoryProductMap::mAleadyCreated){ if(x.second.size() == sizeof...(Ranges)){ check = sfor_p<0,sizeof...(Ranges)> ( [&](auto i) { return reinterpret_cast( std::get(ptp).get() ) == x.second[i]; }, [&](auto a, auto b) { return a and b; } ); if(check){ out = x.first; break; } } } if(not check){ vector pv(sizeof...(Ranges)); sfor_pn<0,sizeof...(Ranges)> ( [&](auto i) { pv[i] = reinterpret_cast( std::get(ptp).get() ); return 0; } ); MultiRangeFactoryProductMap::mAleadyCreated[mProd] = pv; out = mProd; } return out; } /****************** * MultiRange * ******************/ template MultiRange::MultiRange(const std::shared_ptr&... rs) : mSpace(std::make_tuple(rs...)) {} template MultiRange::MultiRange(const Space& space) : mSpace( space ) {} template template auto MultiRange::get() const -> decltype( *std::get( mSpace ) )& { return *std::get(mSpace); } template size_t MultiRange::getMeta(const MetaType& metaPos) const { return RangeHelper::getMeta(mSpace,metaPos); } template template auto MultiRange::getPtr() const -> decltype( std::get( mSpace ) )& { return std::get(mSpace); } template std::shared_ptr MultiRange::sub(size_t num) const { assert(num < sizeof...(Indices)); return sforx_p<0,sizeof...(Indices)> ( [&](auto i) { return std::dynamic_pointer_cast(std::get(mSpace)); }, [&](auto i) { return num != i;} ); } template size_t MultiRange::dim() const { return sdim; } template size_t MultiRange::size() const { return sfor_p<0,sizeof...(Ranges)> ( [&](auto i) { return std::get(mSpace)->size(); }, [&](auto a, auto b) { return a * b; } ); } template SpaceType MultiRange::spaceType() const { return SpaceType::ANY; } template const typename MultiRange::Space& MultiRange::space() const { return mSpace; } template vector MultiRange::typeNum() const { vector o; RangeHelper::getTypeNum(o,mSpace); return o; } template size_t MultiRange::cmeta(char* target, size_t pos) const { const size_t off = cmetaSize(); MetaType* xtarget = reinterpret_cast(target); return RangeHelper::getCMeta(xtarget,pos,mSpace,off); } template size_t MultiRange::cmetaSize() const { return RangeHelper::getCMetaSize<0>(mSpace); } template std::string MultiRange::stringMeta(size_t pos) const { auto i = begin(); i = pos; return "[" + RangeHelper::getStringMeta<0>(i) + "]"; } template vector MultiRange::data() const { DataHeader h = dataHeader(); vector out; //out.reserve(h.metaSize + sizeof(DataHeader)); char* hcp = reinterpret_cast(&h); out.insert(out.end(), hcp, hcp + sizeof(DataHeader)); sfor_pn<0,sizeof...(Ranges)> ( [&](auto i) { vector part = std::get(mSpace)->data(); out.insert(out.end(), part.begin(), part.end()); return 0; } ); return out; } template DataHeader MultiRange::dataHeader() const { DataHeader h; h.spaceType = static_cast( SpaceType::ANY ); h.metaSize = sizeof...(Ranges); h.multiple = 1; return h; } template typename MultiRange::IndexType MultiRange::begin() const { MultiIndex i( std::dynamic_pointer_cast > ( std::shared_ptr( RB::mThis ) ) ); i = 0; return i; } template typename MultiRange::IndexType MultiRange::end() const { MultiIndex i( std::dynamic_pointer_cast > ( std::shared_ptr( RB::mThis )) ); i = size(); return i; } template template auto MultiRange::cat(const std::shared_ptr >& erange) -> std::shared_ptr > { auto crange = std::tuple_cat(mSpace, erange->space()); MultiRangeFactory rf(crange); return std::dynamic_pointer_cast >(rf.create()); } } #endif