1 // Boost.Geometry (aka GGL, Generic Geometry Library) 2 3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. 4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. 5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. 6 7 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library 8 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. 9 10 // Use, modification and distribution is subject to the Boost Software License, 11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 12 // http://www.boost.org/LICENSE_1_0.txt) 13 14 #ifndef BOOST_GEOMETRY_ITERATORS_EVER_CIRCLING_ITERATOR_HPP 15 #define BOOST_GEOMETRY_ITERATORS_EVER_CIRCLING_ITERATOR_HPP 16 17 #include <boost/range.hpp> 18 #include <boost/iterator/iterator_adaptor.hpp> 19 #include <boost/iterator/iterator_categories.hpp> 20 21 #include <boost/geometry/iterators/base.hpp> 22 23 namespace boost { namespace geometry 24 { 25 26 /*! 27 \brief Iterator which ever circles through a range 28 \tparam Iterator iterator on which this class is based on 29 \ingroup iterators 30 \details If the iterator arrives at range.end() it restarts from the 31 beginning. So it has to be stopped in another way. 32 Don't call for(....; it++) because it will turn in an endless loop 33 \note Name inspired on David Bowie's 34 "Chant Of The Ever Circling Skeletal Family" 35 */ 36 template <typename Iterator> 37 struct ever_circling_iterator : 38 public detail::iterators::iterator_base 39 < 40 ever_circling_iterator<Iterator>, 41 Iterator 42 > 43 { 44 friend class boost::iterator_core_access; 45 ever_circling_iteratorboost::geometry::ever_circling_iterator46 explicit inline ever_circling_iterator(Iterator begin, Iterator end, 47 bool skip_first = false) 48 : m_begin(begin) 49 , m_end(end) 50 , m_skip_first(skip_first) 51 { 52 this->base_reference() = begin; 53 } 54 ever_circling_iteratorboost::geometry::ever_circling_iterator55 explicit inline ever_circling_iterator(Iterator begin, Iterator end, Iterator start, 56 bool skip_first = false) 57 : m_begin(begin) 58 , m_end(end) 59 , m_skip_first(skip_first) 60 { 61 this->base_reference() = start; 62 } 63 64 /// Navigate to a certain position, should be in [start .. end], if at end 65 /// it will circle again. movetoboost::geometry::ever_circling_iterator66 inline void moveto(Iterator it) 67 { 68 this->base_reference() = it; 69 check_end(); 70 } 71 72 private: 73 incrementboost::geometry::ever_circling_iterator74 inline void increment(bool possibly_skip = true) 75 { 76 (this->base_reference())++; 77 check_end(possibly_skip); 78 } 79 check_endboost::geometry::ever_circling_iterator80 inline void check_end(bool possibly_skip = true) 81 { 82 if (this->base() == this->m_end) 83 { 84 this->base_reference() = this->m_begin; 85 if (m_skip_first && possibly_skip) 86 { 87 increment(false); 88 } 89 } 90 } 91 92 Iterator m_begin; 93 Iterator m_end; 94 bool m_skip_first; 95 }; 96 97 template <typename Range> 98 struct ever_circling_range_iterator 99 : public boost::iterator_facade 100 < 101 ever_circling_range_iterator<Range>, 102 typename boost::range_value<Range>::type const, 103 boost::random_access_traversal_tag, 104 typename boost::range_reference<Range const>::type, 105 typename boost::range_difference<Range>::type 106 > 107 { 108 private: 109 typedef boost::iterator_facade 110 < 111 ever_circling_range_iterator<Range>, 112 typename boost::range_value<Range>::type const, 113 boost::random_access_traversal_tag, 114 typename boost::range_reference<Range const>::type, 115 typename boost::range_difference<Range>::type 116 > base_type; 117 118 public: 119 /// Constructor including the range it is based on ever_circling_range_iteratorboost::geometry::ever_circling_range_iterator120 explicit inline ever_circling_range_iterator(Range& range) 121 : m_range(&range) 122 , m_iterator(boost::begin(range)) 123 , m_size(boost::size(range)) 124 , m_index(0) 125 {} 126 127 /// Default constructor ever_circling_range_iteratorboost::geometry::ever_circling_range_iterator128 explicit inline ever_circling_range_iterator() 129 : m_range(NULL) 130 , m_size(0) 131 , m_index(0) 132 {} 133 134 typedef typename base_type::reference reference; 135 typedef typename base_type::difference_type difference_type; 136 137 private: 138 friend class boost::iterator_core_access; 139 dereferenceboost::geometry::ever_circling_range_iterator140 inline reference dereference() const 141 { 142 return *m_iterator; 143 } 144 distance_toboost::geometry::ever_circling_range_iterator145 inline difference_type distance_to(ever_circling_range_iterator<Range> const& other) const 146 { 147 return other.m_index - this->m_index; 148 } 149 equalboost::geometry::ever_circling_range_iterator150 inline bool equal(ever_circling_range_iterator<Range> const& other) const 151 { 152 return this->m_range == other.m_range 153 && this->m_index == other.m_index; 154 } 155 incrementboost::geometry::ever_circling_range_iterator156 inline void increment() 157 { 158 ++m_index; 159 if (m_index >= 0 && m_index < m_size) 160 { 161 ++m_iterator; 162 } 163 else 164 { 165 update_iterator(); 166 } 167 } 168 decrementboost::geometry::ever_circling_range_iterator169 inline void decrement() 170 { 171 --m_index; 172 if (m_index >= 0 && m_index < m_size) 173 { 174 --m_iterator; 175 } 176 else 177 { 178 update_iterator(); 179 } 180 } 181 advanceboost::geometry::ever_circling_range_iterator182 inline void advance(difference_type n) 183 { 184 if (m_index >= 0 && m_index < m_size 185 && m_index + n >= 0 && m_index + n < m_size) 186 { 187 m_index += n; 188 m_iterator += n; 189 } 190 else 191 { 192 m_index += n; 193 update_iterator(); 194 } 195 } 196 update_iteratorboost::geometry::ever_circling_range_iterator197 inline void update_iterator() 198 { 199 while (m_index < 0) 200 { 201 m_index += m_size; 202 } 203 m_index = m_index % m_size; 204 this->m_iterator = boost::begin(*m_range) + m_index; 205 } 206 207 Range* m_range; 208 typename boost::range_iterator<Range>::type m_iterator; 209 difference_type m_size; 210 difference_type m_index; 211 }; 212 213 214 }} // namespace boost::geometry 215 216 #endif // BOOST_GEOMETRY_ITERATORS_EVER_CIRCLING_ITERATOR_HPP 217