123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- /* 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 <boost/iterator/iterator_facade.hpp>
- #include <boost/poly_collection/detail/iterator_traits.hpp>
- #include <typeinfo>
- #include <utility>
- namespace boost{
- namespace poly_collection{
- namespace detail{
- /* breakdown of an iterator range into local_base_iterator segments */
- template<typename PolyCollectionIterator>
- class segment_splitter
- {
- using traits=iterator_traits<PolyCollectionIterator>;
- 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,info,std::input_iterator_tag,info>
- {
- 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<typename PolyCollectionIterator>
- segment_splitter<PolyCollectionIterator>
- 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<typename PolyCollectionIterator,typename F>
- void for_each_segment(
- const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
- {
- using traits=iterator_traits<PolyCollectionIterator>;
- using info=typename segment_splitter<PolyCollectionIterator>::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<typename PolyCollectionIterator,typename F>
- 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
|