/* Copyright 2016-2017 Joaquin M Lopez Munoz. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * See http://www.boost.org/libs/poly_collection for library home page. */ #ifndef BOOST_POLY_COLLECTION_DETAIL_SEGMENT_SPLIT_HPP #define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_SPLIT_HPP #if defined(_MSC_VER) #pragma once #endif #include #include #include #include namespace boost{ namespace poly_collection{ namespace detail{ /* breakdown of an iterator range into local_base_iterator segments */ template class segment_splitter { using traits=iterator_traits; using local_base_iterator=typename traits::local_base_iterator; using base_segment_info_iterator=typename traits::base_segment_info_iterator; public: struct info { const std::type_info& type_info()const noexcept{return *pinfo_;} local_base_iterator begin()const noexcept{return begin_;} local_base_iterator end()const noexcept{return end_;} const std::type_info* pinfo_; local_base_iterator begin_,end_; }; struct iterator:iterator_facade { iterator()=default; private: friend class segment_splitter; friend class boost::iterator_core_access; iterator( base_segment_info_iterator it, const PolyCollectionIterator& first,const PolyCollectionIterator& last): it{it},pfirst{&first},plast{&last}{} iterator( const PolyCollectionIterator& first,const PolyCollectionIterator& last): it{traits::base_segment_info_iterator_from(first)}, pfirst{&first},plast{&last} {} info dereference()const noexcept { return { &it->type_info(), it==traits::base_segment_info_iterator_from(*pfirst)? traits::local_base_iterator_from(*pfirst):it->begin(), it==traits::base_segment_info_iterator_from(*plast)? traits::local_base_iterator_from(*plast):it->end() }; } bool equal(const iterator& x)const noexcept{return it==x.it;} void increment()noexcept{++it;} base_segment_info_iterator it; const PolyCollectionIterator* pfirst; const PolyCollectionIterator* plast; }; segment_splitter( const PolyCollectionIterator& first,const PolyCollectionIterator& last): pfirst{&first},plast{&last}{} iterator begin()const noexcept{return {*pfirst,*plast};} iterator end()const noexcept { auto slast=traits::base_segment_info_iterator_from(*plast); if(slast!=traits::end_base_segment_info_iterator_from(*plast))++slast; return {slast,*plast,*plast}; } private: const PolyCollectionIterator* pfirst; const PolyCollectionIterator* plast; }; template segment_splitter segment_split( const PolyCollectionIterator& first,const PolyCollectionIterator& last) { return {first,last}; } #if 1 /* equivalent to for(auto i:segment_split(first,last))f(i) */ template void for_each_segment( const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f) { using traits=iterator_traits; using info=typename segment_splitter::info; auto sfirst=traits::base_segment_info_iterator_from(first), slast=traits::base_segment_info_iterator_from(last), send=traits::end_base_segment_info_iterator_from(last); auto lbfirst=traits::local_base_iterator_from(first), lblast=traits::local_base_iterator_from(last); if(sfirst!=slast){ for(;;){ f(info{&sfirst->type_info(),lbfirst,sfirst->end()}); ++sfirst; if(sfirst==slast)break; lbfirst=sfirst->begin(); } if(sfirst!=send)f(info{&sfirst->type_info(),sfirst->begin(),lblast}); } else if(sfirst!=send){ f(info{&sfirst->type_info(),lbfirst,lblast}); } } #else template void for_each_segment( const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f) { for(auto i:segment_split(first,last))f(i); } #endif } /* namespace poly_collection::detail */ } /* namespace poly_collection */ } /* namespace boost */ #endif