aimstil  5.0.5
cyclic_iterator.h
Go to the documentation of this file.
1 #ifndef CYCLIC_ITERATOR_H_
2 #define CYCLIC_ITERATOR_H_
3 
4 
5 namespace til
6 {
7 
8  //---------------------------------------------------------------------------
9 
10  template < typename TContainer, typename TIterator >
11  inline TIterator cyclic_advance(TIterator i, TContainer &c)
12  {
13  if (++i == c.end()) i = c.begin();
14  return i;
15  }
16 
17  //---------------------------------------------------------------------------
18 
19  namespace detail
20  {
21 
22  //-------------------------------------------------------------------------
23 
24 
28  // We don't derive from the iterator anymore, for several reasons. The first is that TIterator might
29  // be a naked pointer, as it is the case for boost::array. Although, of course, one could specialize
30  // cyclic_iterator for pointers. The second reason is that this is not safe to expose functionality
31  // of the old iterator, as some functions may be broken for the cyclic iterator. In other words, we
32  // expose the part of what we know should work. The other functionality can be retrieve with explicit
33  // getting of the underlying iterator. Of course this is not ideal as well, because in some situations, we
34  // would like to use it without knowing we are dealing with a cyclic iterator.
35  template < typename TIterator >
37  // : public TIterator
38  {
39  public: // typedefs -------------------------------------------------------
40 
41  //typedef TIterator Base;
42 
43  public: // constructors ---------------------------------------------------
44 
45  cyclic_iterator_base() : m_iterator(), m_begin(), m_end() {}
46  // TODO: it's not clear whether this should initialise the iterator as well
47  template < typename TContainer >
48  cyclic_iterator_base(TContainer & c) : m_iterator(), m_begin(c.begin()), m_end(c.end()) {}
50  template < typename TContainer >
51  cyclic_iterator_base(TContainer &c, const TIterator & i) : m_iterator(i), m_begin(c.begin()), m_end(c.end())
52  {
53  // we treat end as a special case because it is one very common case where
54  // the user would provide an iterator lying outside the container.
55  // TODO: I guess this won't work with reverse iterators because of the end()...
56  if (m_iterator == m_end) m_iterator = m_begin;
57  }
58 
59  public: // functions ------------------------------------------------------
60 
61  // TODO: operator* does not necessarily return a reference... use a kind of type_of instead.
62 
63  typename std::iterator_traits<TIterator>::reference
64  operator*() { return *m_iterator; }
65 
66  const typename std::iterator_traits<TIterator>::reference
67  operator*() const { return *m_iterator; }
68 
69  void operator++()
70  {
71  ++m_iterator;
72  if (m_iterator == m_end) m_iterator = m_begin;
73  }
74 
75  void operator--()
76  {
77  if (m_iterator == m_begin) m_iterator = m_end;
78  --m_iterator;
79  }
80 
81  bool operator!=(const TIterator &i)
82  {
83  // I am just adding an assert to track eventual problems when a cyclic
84  // iterator was mistakingly put in a 'for' loop and compared to end()
85  assert(i != m_end);
86  return m_iterator != i;
87  }
88 
89  // TODO: overload other functions as well. This is one of the danger of
90  // deriving from a type: you are exposing all methods! E.g. operator+=
91  // still works in the same (non-cyclic) way. This is of course quite a
92  // proble, when we inherit from an unknown (template argument) type...
93 
94 
95  private: // data ----------------------------------------------------------
96 
97  TIterator m_iterator;
98  TIterator m_begin;
99  TIterator m_end;
100  };
101 
102  //-------------------------------------------------------------------------
103 
104  } // namespace detail
105 
106  //---------------------------------------------------------------------------
107 
110  template < typename TContainer >
111  class const_cyclic_iterator
112  : public detail::cyclic_iterator_base<typename TContainer::const_iterator>
113  {
114  public: // typedefs ---------------------------------------------------------
116  public: // constructors -----------------------------------------------------
117  const_cyclic_iterator() : Base() {}
118  const_cyclic_iterator(const TContainer & c) : Base(c) {}
119  const_cyclic_iterator(const TContainer & c, const typename TContainer::const_iterator & i) : Base(c,i) {}
120  };
121 
122  //---------------------------------------------------------------------------
123 
126  template < typename TContainer >
127  class cyclic_iterator
128  : public detail::cyclic_iterator_base<typename TContainer::iterator>
129  {
130  public: // typedefs ---------------------------------------------------------
132  public: // constructors -----------------------------------------------------
133  cyclic_iterator() : Base() {}
134  cyclic_iterator(TContainer & c) : Base(c) {}
135  cyclic_iterator(TContainer & c, const typename TContainer::iterator & i) : Base(c, i) {}
136  };
137 
138  //---------------------------------------------------------------------------
139 
140 } // namespace til
141 
142 
143 
144 #endif /*CYCLIC_ITERATOR_H_*/
const_cyclic_iterator(const TContainer &c)
bool operator!=(const TIterator &i)
cyclic_iterator_base(TContainer &c, const TIterator &i)
NB: it is assumed that i does point on one of the element of c (end() accepted)
Belongs to package Box Do not include directly, include til/Box.h instead.
Definition: Accumulator.h:10
A const cyclic iterator is a const iterator that goes back to the begining of the container when it r...
std::iterator_traits< TIterator >::reference operator*()
cyclic_iterator(TContainer &c, const typename TContainer::iterator &i)
TIterator cyclic_advance(TIterator i, TContainer &c)
detail::cyclic_iterator_base< typename TContainer::const_iterator > Base
A cyclic iterator is an iterator that goes back to the begining of the container when it reaches the ...
const_cyclic_iterator(const TContainer &c, const typename TContainer::const_iterator &i)
cyclic_iterator(TContainer &c)
const std::iterator_traits< TIterator >::reference operator*() const
detail::cyclic_iterator_base< typename TContainer::iterator > Base
TODO: when implementing the operator+=, it might be that we need to split the class in different part...