1 // Boost.Geometry (aka GGL, Generic Geometry Library) 2 3 // Copyright (c) 2014, Oracle and/or its affiliates. 4 5 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle 6 7 // Licensed under the Boost Software License version 1.0. 8 // http://www.boost.org/users/license.html 9 10 #ifndef BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP 11 #define BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP 12 13 #include <boost/mpl/assert.hpp> 14 #include <boost/type_traits/is_convertible.hpp> 15 #include <boost/iterator.hpp> 16 #include <boost/iterator/iterator_facade.hpp> 17 #include <boost/iterator/iterator_categories.hpp> 18 19 #include <boost/geometry/core/assert.hpp> 20 21 namespace boost { namespace geometry 22 { 23 24 25 26 template 27 < 28 typename OuterIterator, 29 typename InnerIterator, 30 typename Value, 31 typename AccessInnerBegin, 32 typename AccessInnerEnd, 33 typename Reference = Value& 34 > 35 class flatten_iterator 36 : public boost::iterator_facade 37 < 38 flatten_iterator 39 < 40 OuterIterator, 41 InnerIterator, 42 Value, 43 AccessInnerBegin, 44 AccessInnerEnd, 45 Reference 46 >, 47 Value, 48 boost::bidirectional_traversal_tag, 49 Reference 50 > 51 { 52 private: 53 OuterIterator m_outer_it, m_outer_end; 54 InnerIterator m_inner_it; 55 56 public: 57 typedef OuterIterator outer_iterator_type; 58 typedef InnerIterator inner_iterator_type; 59 60 // default constructor flatten_iterator()61 flatten_iterator() {} 62 63 // for begin flatten_iterator(OuterIterator outer_it,OuterIterator outer_end)64 flatten_iterator(OuterIterator outer_it, OuterIterator outer_end) 65 : m_outer_it(outer_it), m_outer_end(outer_end) 66 { 67 advance_through_empty(); 68 } 69 70 // for end flatten_iterator(OuterIterator outer_end)71 flatten_iterator(OuterIterator outer_end) 72 : m_outer_it(outer_end), m_outer_end(outer_end) 73 {} 74 75 template 76 < 77 typename OtherOuterIterator, typename OtherInnerIterator, 78 typename OtherValue, 79 typename OtherAccessInnerBegin, typename OtherAccessInnerEnd, 80 typename OtherReference 81 > flatten_iterator(flatten_iterator<OtherOuterIterator,OtherInnerIterator,OtherValue,OtherAccessInnerBegin,OtherAccessInnerEnd,OtherReference> const & other)82 flatten_iterator(flatten_iterator 83 < 84 OtherOuterIterator, 85 OtherInnerIterator, 86 OtherValue, 87 OtherAccessInnerBegin, 88 OtherAccessInnerEnd, 89 OtherReference 90 > const& other) 91 : m_outer_it(other.m_outer_it), 92 m_outer_end(other.m_outer_end), 93 m_inner_it(other.m_inner_it) 94 { 95 static const bool are_conv 96 = boost::is_convertible 97 < 98 OtherOuterIterator, OuterIterator 99 >::value 100 && boost::is_convertible 101 < 102 OtherInnerIterator, InnerIterator 103 >::value; 104 105 BOOST_MPL_ASSERT_MSG((are_conv), 106 NOT_CONVERTIBLE, 107 (types<OtherOuterIterator, OtherInnerIterator>)); 108 } 109 operator =(flatten_iterator const & other)110 flatten_iterator& operator=(flatten_iterator const& other) 111 { 112 m_outer_it = other.m_outer_it; 113 m_outer_end = other.m_outer_end; 114 // avoid assigning an iterator having singular value 115 if ( other.m_outer_it != other.m_outer_end ) 116 { 117 m_inner_it = other.m_inner_it; 118 } 119 return *this; 120 } 121 122 private: 123 friend class boost::iterator_core_access; 124 125 template 126 < 127 typename Outer, 128 typename Inner, 129 typename V, 130 typename InnerBegin, 131 typename InnerEnd, 132 typename R 133 > 134 friend class flatten_iterator; 135 empty(OuterIterator outer_it)136 static inline bool empty(OuterIterator outer_it) 137 { 138 return AccessInnerBegin::apply(*outer_it) 139 == AccessInnerEnd::apply(*outer_it); 140 } 141 advance_through_empty()142 inline void advance_through_empty() 143 { 144 while ( m_outer_it != m_outer_end && empty(m_outer_it) ) 145 { 146 ++m_outer_it; 147 } 148 149 if ( m_outer_it != m_outer_end ) 150 { 151 m_inner_it = AccessInnerBegin::apply(*m_outer_it); 152 } 153 } 154 dereference() const155 inline Reference dereference() const 156 { 157 BOOST_GEOMETRY_ASSERT( m_outer_it != m_outer_end ); 158 BOOST_GEOMETRY_ASSERT( m_inner_it != AccessInnerEnd::apply(*m_outer_it) ); 159 return *m_inner_it; 160 } 161 162 163 template 164 < 165 typename OtherOuterIterator, 166 typename OtherInnerIterator, 167 typename OtherValue, 168 typename OtherAccessInnerBegin, 169 typename OtherAccessInnerEnd, 170 typename OtherReference 171 > equal(flatten_iterator<OtherOuterIterator,OtherInnerIterator,OtherValue,OtherAccessInnerBegin,OtherAccessInnerEnd,OtherReference> const & other) const172 inline bool equal(flatten_iterator 173 < 174 OtherOuterIterator, 175 OtherInnerIterator, 176 OtherValue, 177 OtherAccessInnerBegin, 178 OtherAccessInnerEnd, 179 OtherReference 180 > const& other) const 181 { 182 if ( m_outer_it != other.m_outer_it ) 183 { 184 return false; 185 } 186 187 if ( m_outer_it == m_outer_end ) 188 { 189 return true; 190 } 191 192 return m_inner_it == other.m_inner_it; 193 } 194 increment()195 inline void increment() 196 { 197 BOOST_GEOMETRY_ASSERT( m_outer_it != m_outer_end ); 198 BOOST_GEOMETRY_ASSERT( m_inner_it != AccessInnerEnd::apply(*m_outer_it) ); 199 200 ++m_inner_it; 201 if ( m_inner_it == AccessInnerEnd::apply(*m_outer_it) ) 202 { 203 ++m_outer_it; 204 advance_through_empty(); 205 } 206 } 207 decrement()208 inline void decrement() 209 { 210 if ( m_outer_it == m_outer_end 211 || m_inner_it == AccessInnerBegin::apply(*m_outer_it) ) 212 { 213 do 214 { 215 --m_outer_it; 216 } 217 while ( empty(m_outer_it) ); 218 m_inner_it = AccessInnerEnd::apply(*m_outer_it); 219 } 220 --m_inner_it; 221 } 222 }; 223 224 225 226 }} // namespace boost::geometry 227 228 229 #endif // BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP 230