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