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.hpp> 19 #include <boost/iterator/iterator_adaptor.hpp> 20 #include <boost/iterator/iterator_categories.hpp> 21 22 #include <boost/geometry/iterators/base.hpp> 23 24 namespace boost { namespace geometry 25 { 26 27 /*! 28 \brief Iterator which ever circles through a range 29 \tparam Iterator iterator on which this class is based on 30 \ingroup iterators 31 \details If the iterator arrives at range.end() it restarts from the 32 beginning. So it has to be stopped in another way. 33 Don't call for(....; it++) because it will turn in an endless loop 34 \note Name inspired on David Bowie's 35 "Chant Of The Ever Circling Skeletal Family" 36 */ 37 template <typename Iterator> 38 struct ever_circling_iterator : 39 public detail::iterators::iterator_base 40 < 41 ever_circling_iterator<Iterator>, 42 Iterator 43 > 44 { 45 friend class boost::iterator_core_access; 46 ever_circling_iteratorboost::geometry::ever_circling_iterator47 explicit inline ever_circling_iterator(Iterator begin, Iterator end, 48 bool skip_first = false) 49 : m_begin(begin) 50 , m_end(end) 51 , m_skip_first(skip_first) 52 { 53 this->base_reference() = begin; 54 } 55 ever_circling_iteratorboost::geometry::ever_circling_iterator56 explicit inline ever_circling_iterator(Iterator begin, Iterator end, Iterator start, 57 bool skip_first = false) 58 : m_begin(begin) 59 , m_end(end) 60 , m_skip_first(skip_first) 61 { 62 this->base_reference() = start; 63 } 64 65 /// Navigate to a certain position, should be in [start .. end], if at end 66 /// it will circle again. movetoboost::geometry::ever_circling_iterator67 inline void moveto(Iterator it) 68 { 69 this->base_reference() = it; 70 check_end(); 71 } 72 73 private: 74 incrementboost::geometry::ever_circling_iterator75 inline void increment(bool possibly_skip = true) 76 { 77 (this->base_reference())++; 78 check_end(possibly_skip); 79 } 80 check_endboost::geometry::ever_circling_iterator81 inline void check_end(bool possibly_skip = true) 82 { 83 if (this->base() == this->m_end) 84 { 85 this->base_reference() = this->m_begin; 86 if (m_skip_first && possibly_skip) 87 { 88 increment(false); 89 } 90 } 91 } 92 93 Iterator m_begin; 94 Iterator m_end; 95 bool m_skip_first; 96 }; 97 98 template <typename Range> 99 struct ever_circling_range_iterator 100 : public boost::iterator_facade 101 < 102 ever_circling_range_iterator<Range>, 103 typename boost::range_value<Range>::type const, 104 boost::random_access_traversal_tag 105 > 106 { 107 /// Constructor including the range it is based on ever_circling_range_iteratorboost::geometry::ever_circling_range_iterator108 explicit inline ever_circling_range_iterator(Range& range) 109 : m_range(&range) 110 , m_iterator(boost::begin(range)) 111 , m_size(boost::size(range)) 112 , m_index(0) 113 {} 114 115 /// Default constructor ever_circling_range_iteratorboost::geometry::ever_circling_range_iterator116 explicit inline ever_circling_range_iterator() 117 : m_range(NULL) 118 , m_size(0) 119 , m_index(0) 120 {} 121 122 typedef std::ptrdiff_t difference_type; 123 124 private: 125 friend class boost::iterator_core_access; 126 dereferenceboost::geometry::ever_circling_range_iterator127 inline typename boost::range_value<Range>::type const& dereference() const 128 { 129 return *m_iterator; 130 } 131 distance_toboost::geometry::ever_circling_range_iterator132 inline difference_type distance_to(ever_circling_range_iterator<Range> const& other) const 133 { 134 return other.m_index - this->m_index; 135 } 136 equalboost::geometry::ever_circling_range_iterator137 inline bool equal(ever_circling_range_iterator<Range> const& other) const 138 { 139 return this->m_range == other.m_range 140 && this->m_index == other.m_index; 141 } 142 incrementboost::geometry::ever_circling_range_iterator143 inline void increment() 144 { 145 ++m_index; 146 if (m_index >= 0 && m_index < m_size) 147 { 148 ++m_iterator; 149 } 150 else 151 { 152 update_iterator(); 153 } 154 } 155 decrementboost::geometry::ever_circling_range_iterator156 inline void decrement() 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 advanceboost::geometry::ever_circling_range_iterator169 inline void advance(difference_type n) 170 { 171 if (m_index >= 0 && m_index < m_size 172 && m_index + n >= 0 && m_index + n < m_size) 173 { 174 m_index += n; 175 m_iterator += n; 176 } 177 else 178 { 179 m_index += n; 180 update_iterator(); 181 } 182 } 183 update_iteratorboost::geometry::ever_circling_range_iterator184 inline void update_iterator() 185 { 186 while (m_index < 0) 187 { 188 m_index += m_size; 189 } 190 m_index = m_index % m_size; 191 this->m_iterator = boost::begin(*m_range) + m_index; 192 } 193 194 Range* m_range; 195 typename boost::range_iterator<Range>::type m_iterator; 196 difference_type m_size; 197 difference_type m_index; 198 }; 199 200 201 }} // namespace boost::geometry 202 203 #endif // BOOST_GEOMETRY_ITERATORS_EVER_CIRCLING_ITERATOR_HPP 204