• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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