213 lines
5.4 KiB
C++
213 lines
5.4 KiB
C++
// 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)
|
|
{}
|
|
|
|
inline ever_circling_range_iterator<Range>& operator=(ever_circling_range_iterator<Range> const& source)
|
|
{
|
|
m_range = source.m_range;
|
|
m_iterator = source.m_iterator;
|
|
m_size = source.m_size;
|
|
m_index = source.m_index;
|
|
return *this;
|
|
}
|
|
|
|
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
|