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