1 /* Copyright 2016-2017 Joaquin M Lopez Munoz.
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * http://www.boost.org/LICENSE_1_0.txt)
6 * See http://www.boost.org/libs/poly_collection for library home page.
9 #ifndef BOOST_POLY_COLLECTION_DETAIL_SEGMENT_SPLIT_HPP
10 #define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_SPLIT_HPP
16 #include <boost/iterator/iterator_facade.hpp>
17 #include <boost/poly_collection/detail/iterator_traits.hpp>
23 namespace poly_collection{
27 /* breakdown of an iterator range into local_base_iterator segments */
29 template<typename PolyCollectionIterator>
30 class segment_splitter
32 using traits=iterator_traits<PolyCollectionIterator>;
33 using local_base_iterator=typename traits::local_base_iterator;
34 using base_segment_info_iterator=typename traits::base_segment_info_iterator;
39 const std::type_info& type_info()const noexcept{return *pinfo_;}
40 local_base_iterator begin()const noexcept{return begin_;}
41 local_base_iterator end()const noexcept{return end_;}
43 const std::type_info* pinfo_;
44 local_base_iterator begin_,end_;
47 struct iterator:iterator_facade<iterator,info,std::input_iterator_tag,info>
52 friend class segment_splitter;
53 friend class boost::iterator_core_access;
56 base_segment_info_iterator it,
57 const PolyCollectionIterator& first,const PolyCollectionIterator& last):
58 it{it},pfirst{&first},plast{&last}{}
60 const PolyCollectionIterator& first,const PolyCollectionIterator& last):
61 it{traits::base_segment_info_iterator_from(first)},
62 pfirst{&first},plast{&last}
65 info dereference()const noexcept
69 it==traits::base_segment_info_iterator_from(*pfirst)?
70 traits::local_base_iterator_from(*pfirst):it->begin(),
71 it==traits::base_segment_info_iterator_from(*plast)?
72 traits::local_base_iterator_from(*plast):it->end()
76 bool equal(const iterator& x)const noexcept{return it==x.it;}
77 void increment()noexcept{++it;}
79 base_segment_info_iterator it;
80 const PolyCollectionIterator* pfirst;
81 const PolyCollectionIterator* plast;
85 const PolyCollectionIterator& first,const PolyCollectionIterator& last):
86 pfirst{&first},plast{&last}{}
88 iterator begin()const noexcept{return {*pfirst,*plast};}
90 iterator end()const noexcept
92 auto slast=traits::base_segment_info_iterator_from(*plast);
93 if(slast!=traits::end_base_segment_info_iterator_from(*plast))++slast;
94 return {slast,*plast,*plast};
98 const PolyCollectionIterator* pfirst;
99 const PolyCollectionIterator* plast;
102 template<typename PolyCollectionIterator>
103 segment_splitter<PolyCollectionIterator>
105 const PolyCollectionIterator& first,const PolyCollectionIterator& last)
111 /* equivalent to for(auto i:segment_split(first,last))f(i) */
113 template<typename PolyCollectionIterator,typename F>
114 void for_each_segment(
115 const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
117 using traits=iterator_traits<PolyCollectionIterator>;
118 using info=typename segment_splitter<PolyCollectionIterator>::info;
120 auto sfirst=traits::base_segment_info_iterator_from(first),
121 slast=traits::base_segment_info_iterator_from(last),
122 send=traits::end_base_segment_info_iterator_from(last);
123 auto lbfirst=traits::local_base_iterator_from(first),
124 lblast=traits::local_base_iterator_from(last);
128 f(info{&sfirst->type_info(),lbfirst,sfirst->end()});
130 if(sfirst==slast)break;
131 lbfirst=sfirst->begin();
133 if(sfirst!=send)f(info{&sfirst->type_info(),sfirst->begin(),lblast});
135 else if(sfirst!=send){
136 f(info{&sfirst->type_info(),lbfirst,lblast});
140 template<typename PolyCollectionIterator,typename F>
141 void for_each_segment(
142 const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
144 for(auto i:segment_split(first,last))f(i);
148 } /* namespace poly_collection::detail */
150 } /* namespace poly_collection */
152 } /* namespace boost */