| // Boost.Geometry (aka GGL, Generic Geometry Library) |
| |
| // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. |
| // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. |
| // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. |
| |
| // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library |
| // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. |
| |
| // Use, modification and distribution is subject to the Boost Software License, |
| // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| |
| #ifndef BOOST_GEOMETRY_ITERATORS_EVER_CIRCLING_ITERATOR_HPP |
| #define BOOST_GEOMETRY_ITERATORS_EVER_CIRCLING_ITERATOR_HPP |
| |
| #include <boost/range.hpp> |
| #include <boost/iterator.hpp> |
| #include <boost/iterator/iterator_adaptor.hpp> |
| #include <boost/iterator/iterator_categories.hpp> |
| |
| #include <boost/geometry/iterators/base.hpp> |
| |
| namespace boost { namespace geometry |
| { |
| |
| /*! |
| \brief Iterator which ever circles through a range |
| \tparam Iterator iterator on which this class is based on |
| \ingroup iterators |
| \details If the iterator arrives at range.end() it restarts from the |
| beginning. So it has to be stopped in another way. |
| Don't call for(....; it++) because it will turn in an endless loop |
| \note Name inspired on David Bowie's |
| "Chant Of The Ever Circling Skeletal Family" |
| */ |
| template <typename Iterator> |
| struct ever_circling_iterator : |
| public detail::iterators::iterator_base |
| < |
| ever_circling_iterator<Iterator>, |
| Iterator |
| > |
| { |
| friend class boost::iterator_core_access; |
| |
| explicit inline ever_circling_iterator(Iterator begin, Iterator end, |
| bool skip_first = false) |
| : m_begin(begin) |
| , m_end(end) |
| , m_skip_first(skip_first) |
| { |
| this->base_reference() = begin; |
| } |
| |
| explicit inline ever_circling_iterator(Iterator begin, Iterator end, Iterator start, |
| bool skip_first = false) |
| : m_begin(begin) |
| , m_end(end) |
| , m_skip_first(skip_first) |
| { |
| this->base_reference() = start; |
| } |
| |
| /// Navigate to a certain position, should be in [start .. end], if at end |
| /// it will circle again. |
| inline void moveto(Iterator it) |
| { |
| this->base_reference() = it; |
| check_end(); |
| } |
| |
| private: |
| |
| inline void increment(bool possibly_skip = true) |
| { |
| (this->base_reference())++; |
| check_end(possibly_skip); |
| } |
| |
| inline void check_end(bool possibly_skip = true) |
| { |
| if (this->base() == this->m_end) |
| { |
| this->base_reference() = this->m_begin; |
| if (m_skip_first && possibly_skip) |
| { |
| increment(false); |
| } |
| } |
| } |
| |
| Iterator m_begin; |
| Iterator m_end; |
| bool m_skip_first; |
| }; |
| |
| template <typename Range> |
| struct ever_circling_range_iterator |
| : public boost::iterator_facade |
| < |
| ever_circling_range_iterator<Range>, |
| typename boost::range_value<Range>::type const, |
| boost::random_access_traversal_tag |
| > |
| { |
| /// Constructor including the range it is based on |
| explicit inline ever_circling_range_iterator(Range& range) |
| : m_range(&range) |
| , m_iterator(boost::begin(range)) |
| , m_size(boost::size(range)) |
| , m_index(0) |
| {} |
| |
| /// Default constructor |
| explicit inline ever_circling_range_iterator() |
| : m_range(NULL) |
| , m_size(0) |
| , m_index(0) |
| {} |
| |
| typedef std::ptrdiff_t difference_type; |
| |
| private: |
| friend class boost::iterator_core_access; |
| |
| inline typename boost::range_value<Range>::type const& dereference() const |
| { |
| return *m_iterator; |
| } |
| |
| inline difference_type distance_to(ever_circling_range_iterator<Range> const& other) const |
| { |
| return other.m_index - this->m_index; |
| } |
| |
| inline bool equal(ever_circling_range_iterator<Range> const& other) const |
| { |
| return this->m_range == other.m_range |
| && this->m_index == other.m_index; |
| } |
| |
| inline void increment() |
| { |
| ++m_index; |
| if (m_index >= 0 && m_index < m_size) |
| { |
| ++m_iterator; |
| } |
| else |
| { |
| update_iterator(); |
| } |
| } |
| |
| inline void decrement() |
| { |
| --m_index; |
| if (m_index >= 0 && m_index < m_size) |
| { |
| --m_iterator; |
| } |
| else |
| { |
| update_iterator(); |
| } |
| } |
| |
| inline void advance(difference_type n) |
| { |
| if (m_index >= 0 && m_index < m_size |
| && m_index + n >= 0 && m_index + n < m_size) |
| { |
| m_index += n; |
| m_iterator += n; |
| } |
| else |
| { |
| m_index += n; |
| update_iterator(); |
| } |
| } |
| |
| inline void update_iterator() |
| { |
| while (m_index < 0) |
| { |
| m_index += m_size; |
| } |
| m_index = m_index % m_size; |
| this->m_iterator = boost::begin(*m_range) + m_index; |
| } |
| |
| Range* m_range; |
| typename boost::range_iterator<Range>::type m_iterator; |
| difference_type m_size; |
| difference_type m_index; |
| }; |
| |
| |
| }} // namespace boost::geometry |
| |
| #endif // BOOST_GEOMETRY_ITERATORS_EVER_CIRCLING_ITERATOR_HPP |