Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:47:50

0001 /* Copyright 2016-2017 Joaquin M Lopez Munoz.
0002  * Distributed under the Boost Software License, Version 1.0.
0003  * (See accompanying file LICENSE_1_0.txt or copy at
0004  * http://www.boost.org/LICENSE_1_0.txt)
0005  *
0006  * See http://www.boost.org/libs/poly_collection for library home page.
0007  */
0008 
0009 #ifndef BOOST_POLY_COLLECTION_DETAIL_SEGMENT_SPLIT_HPP
0010 #define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_SPLIT_HPP
0011 
0012 #if defined(_MSC_VER)
0013 #pragma once
0014 #endif
0015 
0016 #include <boost/iterator/iterator_facade.hpp>
0017 #include <boost/poly_collection/detail/iterator_traits.hpp>
0018 #include <typeinfo>
0019 #include <utility>
0020 
0021 namespace boost{
0022 
0023 namespace poly_collection{
0024 
0025 namespace detail{
0026 
0027 /* breakdown of an iterator range into local_base_iterator segments */
0028 
0029 template<typename PolyCollectionIterator>
0030 class segment_splitter
0031 {
0032   using traits=iterator_traits<PolyCollectionIterator>;
0033   using local_base_iterator=typename traits::local_base_iterator;
0034   using base_segment_info_iterator=typename traits::base_segment_info_iterator;
0035 
0036 public:
0037   struct info
0038   {
0039     const std::type_info& type_info()const noexcept{return *pinfo_;}
0040     local_base_iterator   begin()const noexcept{return begin_;}
0041     local_base_iterator   end()const noexcept{return end_;}
0042 
0043     const std::type_info* pinfo_;
0044     local_base_iterator   begin_,end_;
0045   };
0046 
0047   struct iterator:iterator_facade<iterator,info,std::input_iterator_tag,info>
0048   {
0049     iterator()=default;
0050 
0051   private:
0052     friend class segment_splitter;
0053     friend class boost::iterator_core_access;
0054 
0055     iterator(
0056       base_segment_info_iterator it,
0057       const PolyCollectionIterator& first,const PolyCollectionIterator& last):
0058       it{it},pfirst{&first},plast{&last}{}
0059     iterator(
0060       const PolyCollectionIterator& first,const PolyCollectionIterator& last):
0061       it{traits::base_segment_info_iterator_from(first)},
0062       pfirst{&first},plast{&last}
0063       {}
0064 
0065     info dereference()const noexcept
0066     {
0067       return {
0068         &it->type_info(),
0069         it==traits::base_segment_info_iterator_from(*pfirst)?
0070           traits::local_base_iterator_from(*pfirst):it->begin(),
0071         it==traits::base_segment_info_iterator_from(*plast)?
0072           traits::local_base_iterator_from(*plast):it->end()
0073       };
0074     }
0075 
0076     bool equal(const iterator& x)const noexcept{return it==x.it;}
0077     void increment()noexcept{++it;}
0078 
0079     base_segment_info_iterator    it;
0080     const PolyCollectionIterator* pfirst;
0081     const PolyCollectionIterator* plast;
0082   };
0083 
0084   segment_splitter(
0085     const PolyCollectionIterator& first,const PolyCollectionIterator& last):
0086     pfirst{&first},plast{&last}{}
0087 
0088   iterator begin()const noexcept{return {*pfirst,*plast};}
0089 
0090   iterator end()const noexcept
0091   {
0092     auto slast=traits::base_segment_info_iterator_from(*plast);
0093     if(slast!=traits::end_base_segment_info_iterator_from(*plast))++slast;
0094     return {slast,*plast,*plast};
0095   }
0096 
0097 private:
0098   const PolyCollectionIterator* pfirst;
0099   const PolyCollectionIterator* plast;
0100 };
0101 
0102 template<typename PolyCollectionIterator>
0103 segment_splitter<PolyCollectionIterator>
0104 segment_split(
0105   const PolyCollectionIterator& first,const PolyCollectionIterator& last)
0106 {
0107   return {first,last};
0108 }
0109 
0110 #if 1
0111 /* equivalent to for(auto i:segment_split(first,last))f(i) */
0112 
0113 template<typename PolyCollectionIterator,typename F>
0114 void for_each_segment(
0115   const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
0116 {
0117   using traits=iterator_traits<PolyCollectionIterator>;
0118   using info=typename segment_splitter<PolyCollectionIterator>::info;
0119 
0120   auto sfirst=traits::base_segment_info_iterator_from(first),
0121        slast=traits::base_segment_info_iterator_from(last),
0122        send=traits::end_base_segment_info_iterator_from(last);
0123   auto lbfirst=traits::local_base_iterator_from(first),
0124        lblast=traits::local_base_iterator_from(last);
0125 
0126   if(sfirst!=slast){
0127     for(;;){
0128       f(info{&sfirst->type_info(),lbfirst,sfirst->end()});
0129       ++sfirst;
0130       if(sfirst==slast)break;
0131       lbfirst=sfirst->begin();
0132     }
0133     if(sfirst!=send)f(info{&sfirst->type_info(),sfirst->begin(),lblast});
0134   }
0135   else if(sfirst!=send){
0136     f(info{&sfirst->type_info(),lbfirst,lblast});
0137   }
0138 }
0139 #else
0140 template<typename PolyCollectionIterator,typename F>
0141 void for_each_segment(
0142   const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
0143 {
0144   for(auto i:segment_split(first,last))f(i);  
0145 }
0146 #endif
0147 
0148 } /* namespace poly_collection::detail */
0149 
0150 } /* namespace poly_collection */
0151 
0152 } /* namespace boost */
0153 
0154 #endif