• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
5  *
6  * See http://www.boost.org/libs/poly_collection for library home page.
7  */
8 
9 #ifndef BOOST_POLY_COLLECTION_DETAIL_ITERATOR_IMPL_HPP
10 #define BOOST_POLY_COLLECTION_DETAIL_ITERATOR_IMPL_HPP
11 
12 #if defined(_MSC_VER)
13 #pragma once
14 #endif
15 
16 #include <boost/iterator/iterator_adaptor.hpp>
17 #include <boost/iterator/iterator_facade.hpp>
18 #include <boost/poly_collection/detail/is_constructible.hpp>
19 #include <boost/poly_collection/detail/iterator_traits.hpp>
20 #include <type_traits>
21 #include <typeinfo>
22 
23 namespace boost{
24 
25 namespace poly_collection{
26 
27 namespace detail{
28 
29 /* Implementations of poly_collection::[const_][local_[base_]]iterator moved
30  * out of class to allow for use in deduced contexts.
31  */
32 
33 template<typename PolyCollection,bool Const>
34 using iterator_impl_value_type=typename std::conditional<
35   Const,
36   const typename PolyCollection::value_type,
37   typename PolyCollection::value_type
38 >::type;
39 
40 template<typename PolyCollection,bool Const>
41 class iterator_impl:
42   public boost::iterator_facade<
43     iterator_impl<PolyCollection,Const>,
44     iterator_impl_value_type<PolyCollection,Const>,
45     boost::forward_traversal_tag
46   >
47 {
48   using segment_type=typename PolyCollection::segment_type;
49   using const_segment_base_iterator=
50     typename PolyCollection::const_segment_base_iterator;
51   using const_segment_base_sentinel=
52     typename PolyCollection::const_segment_base_sentinel;
53   using const_segment_map_iterator=
54     typename PolyCollection::const_segment_map_iterator;
55 
56 public:
57   using value_type=iterator_impl_value_type<PolyCollection,Const>;
58 
59 private:
iterator_impl(const_segment_map_iterator mapit,const_segment_map_iterator mapend)60   iterator_impl(
61     const_segment_map_iterator mapit,
62     const_segment_map_iterator mapend)noexcept:
63     mapit{mapit},mapend{mapend}
64   {
65     next_segment_position();
66   }
67 
iterator_impl(const_segment_map_iterator mapit_,const_segment_map_iterator mapend_,const_segment_base_iterator segpos_)68   iterator_impl(
69     const_segment_map_iterator mapit_,const_segment_map_iterator mapend_,
70     const_segment_base_iterator segpos_)noexcept:
71     mapit{mapit_},mapend{mapend_},segpos{segpos_}
72   {
73     if(mapit!=mapend&&segpos==sentinel()){
74       ++mapit;
75       next_segment_position();
76     }
77   }
78 
79 public:
80   iterator_impl()=default;
81   iterator_impl(const iterator_impl&)=default;
82   iterator_impl& operator=(const iterator_impl&)=default;
83 
84   template<bool Const2,typename std::enable_if<!Const2>::type* =nullptr>
iterator_impl(const iterator_impl<PolyCollection,Const2> & x)85   iterator_impl(const iterator_impl<PolyCollection,Const2>& x):
86     mapit{x.mapit},mapend{x.mapend},segpos{x.segpos}{}
87 
88 private:
89   template<typename,bool>
90   friend class iterator_impl;
91   friend PolyCollection;
92   friend class boost::iterator_core_access;
93   template<typename>
94   friend struct iterator_traits;
95 
dereference() const96   value_type& dereference()const noexcept
97     {return const_cast<value_type&>(*segpos);}
equal(const iterator_impl & x) const98   bool equal(const iterator_impl& x)const noexcept{return segpos==x.segpos;}
99 
increment()100   void increment()noexcept
101   {
102     if(++segpos==sentinel()){
103       ++mapit;
104       next_segment_position();
105     }
106   }
107 
next_segment_position()108   void next_segment_position()noexcept
109   {
110     for(;mapit!=mapend;++mapit){
111       segpos=segment().begin();
112       if(segpos!=sentinel())return;
113     }
114     segpos=nullptr;
115   }
116 
segment()117   segment_type&       segment()noexcept
118     {return const_cast<segment_type&>(mapit->second);}
segment() const119   const segment_type& segment()const noexcept{return mapit->second;}
120 
sentinel() const121   const_segment_base_sentinel sentinel()const noexcept
122     {return segment().sentinel();}
123 
124   const_segment_map_iterator  mapit,mapend;
125   const_segment_base_iterator segpos;
126 };
127 
128 template<typename PolyCollection,bool Const>
129 struct poly_collection_of<iterator_impl<PolyCollection,Const>>
130 {
131   using type=PolyCollection;
132 };
133 
134 template<typename PolyCollection,typename BaseIterator>
135 class local_iterator_impl:
136   public boost::iterator_adaptor<
137     local_iterator_impl<PolyCollection,BaseIterator>,
138     BaseIterator
139   >
140 {
141   using segment_type=typename PolyCollection::segment_type;
142   using segment_base_iterator=typename PolyCollection::segment_base_iterator;
143   using const_segment_map_iterator=
144     typename PolyCollection::const_segment_map_iterator;
145 
146   template<typename Iterator>
local_iterator_impl(const_segment_map_iterator mapit,Iterator it)147   local_iterator_impl(
148     const_segment_map_iterator mapit,
149     Iterator it):
150     local_iterator_impl::iterator_adaptor_{BaseIterator(it)},
151     mapit{mapit}
152   {}
153 
154 public:
155   using base_iterator=BaseIterator;
156 
157   local_iterator_impl()=default;
158   local_iterator_impl(const local_iterator_impl&)=default;
159   local_iterator_impl& operator=(const local_iterator_impl&)=default;
160 
161   template<
162     typename BaseIterator2,
163     typename std::enable_if<
164       std::is_convertible<BaseIterator2,BaseIterator>::value
165     >::type* =nullptr
166   >
local_iterator_impl(const local_iterator_impl<PolyCollection,BaseIterator2> & x)167   local_iterator_impl(
168     const local_iterator_impl<PolyCollection,BaseIterator2>& x):
169     local_iterator_impl::iterator_adaptor_{x.base()},
170     mapit{x.mapit}{}
171 
172   template<
173     typename BaseIterator2,
174     typename std::enable_if<
175       !std::is_convertible<BaseIterator2,BaseIterator>::value&&
176       is_constructible<BaseIterator,BaseIterator2>::value
177     >::type* =nullptr
178   >
local_iterator_impl(const local_iterator_impl<PolyCollection,BaseIterator2> & x)179   explicit local_iterator_impl(
180     const local_iterator_impl<PolyCollection,BaseIterator2>& x):
181     local_iterator_impl::iterator_adaptor_{BaseIterator(x.base())},
182     mapit{x.mapit}{}
183 
184   template<
185     typename BaseIterator2,
186     typename std::enable_if<
187       !is_constructible<BaseIterator,BaseIterator2>::value&&
188       is_constructible<BaseIterator,segment_base_iterator>::value&&
189       is_constructible<BaseIterator2,segment_base_iterator>::value
190     >::type* =nullptr
191   >
local_iterator_impl(const local_iterator_impl<PolyCollection,BaseIterator2> & x)192   explicit local_iterator_impl(
193     const local_iterator_impl<PolyCollection,BaseIterator2>& x):
194     local_iterator_impl::iterator_adaptor_{
195       base_iterator_from(x.segment(),x.base())},
196     mapit{x.mapit}{}
197 
198   /* define [] to avoid Boost.Iterator operator_brackets_proxy mess */
199 
200   template<typename DifferenceType>
201   typename std::iterator_traits<BaseIterator>::reference
operator [](DifferenceType n) const202   operator[](DifferenceType n)const{return *(*this+n);}
203 
204 private:
205   template<typename,typename>
206   friend class local_iterator_impl;
207   friend PolyCollection;
208   template<typename>
209   friend struct iterator_traits;
210 
211   template<typename BaseIterator2>
base_iterator_from(const segment_type & s,BaseIterator2 it)212   static BaseIterator base_iterator_from(
213     const segment_type& s,BaseIterator2 it)
214   {
215     segment_base_iterator bit=s.begin();
216     return BaseIterator{bit+(it-static_cast<BaseIterator2>(bit))};
217   }
218 
base() const219   base_iterator              base()const noexcept
220     {return local_iterator_impl::iterator_adaptor_::base();}
type_info() const221   const std::type_info&      type_info()const{return *mapit->first;}
segment()222   segment_type&              segment()noexcept
223     {return const_cast<segment_type&>(mapit->second);}
segment() const224   const segment_type&        segment()const noexcept{return mapit->second;}
225 
226   const_segment_map_iterator mapit;
227 };
228 
229 template<typename PolyCollection,typename BaseIterator>
230 struct poly_collection_of<local_iterator_impl<PolyCollection,BaseIterator>>
231 {
232   using type=PolyCollection;
233 };
234 
235 
236 } /* namespace poly_collection::detail */
237 
238 } /* namespace poly_collection */
239 
240 } /* namespace boost */
241 
242 #endif
243