[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

counting_iterator.hxx VIGRA

1 /************************************************************************/
2 /* */
3 /* Copyright 2015 by Thorsten Beier */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 #ifndef VIGRA_COUNTING_ITERATOR_HXX
37 #define VIGRA_COUNTING_ITERATOR_HXX
38 
39 
40 #include <cmath>
41 #include <iterator>
42 #include <limits>
43 #include <type_traits>
44 #include "error.hxx"
45 #include "tinyvector.hxx"
46 
47 namespace vigra {
48 
49 namespace detail {
50 
51 template <class T, bool is_float=false>
52 struct CountingIteratorCompare
53 {
54  // use exact comparison for integer counting
55  static bool equal(T left, T right, T /* step */)
56  {
57  return left == right;
58  }
59  static bool not_equal(T left, T right, T /* step */)
60  {
61  return left != right;
62  }
63  static bool less(T left, T right, T step)
64  {
65  // NOTE: the more efficient '(right - left)*step > 0'
66  // fails for unsigned arguments
67  return step > 0
68  ? left < right
69  : left > right;
70  }
71  static bool less_equal(T left, T right, T step)
72  {
73  return step > 0
74  ? left <= right
75  : left >= right;
76  }
77  static bool greater(T left, T right, T step)
78  {
79  return step > 0
80  ? left > right
81  : left < right;
82  }
83  static bool greater_equal(T left, T right, T step)
84  {
85  return step > 0
86  ? left >= right
87  : left <= right;
88  }
89  // integer counting: if the raw distance is not divisible by step,
90  // we must round upwards
91  static std::ptrdiff_t distance(T from, T to, T step)
92  {
93  const double diff = (double(to) - double(from)) / double(step);
94  return diff > 0.0
95  ? (std::ptrdiff_t)std::ceil(diff)
96  : (std::ptrdiff_t)std::floor(diff);
97  }
98 };
99 
100 template <class T>
101 struct CountingIteratorCompare<T, true>
102 {
103  typedef std::numeric_limits<T> limit;
104 
105  // use comparison with tolerance for floating-point counting
106  // (the natural epsilon is 0.5*step)
107  static bool equal(T left, T right, T step)
108  {
109  return std::fabs(right-left) <= 0.5*std::fabs(step);
110  }
111  static bool not_equal(T left, T right, T step)
112  {
113  return std::fabs(right-left) > 0.5*std::fabs(step);
114  }
115  static bool less(T left, T right, T step)
116  {
117  return step > 0.0
118  ? right - left > 0.5*step
119  : right - left < 0.5*step;
120  }
121  static bool less_equal(T left, T right, T step)
122  {
123  return step > 0.0
124  ? left - right < 0.5*step
125  : left - right > 0.5*step;
126  }
127  static bool greater(T left, T right, T step)
128  {
129  return step > 0.0
130  ? left - right > 0.5*step
131  : left - right < 0.5*step;
132  }
133  static bool greater_equal(T left, T right, T step)
134  {
135  return step > 0.0
136  ? right - left < 0.5*step
137  : right - left > 0.5*step;
138  }
139  // floating-point counting: if the raw distance is not divisible by step,
140  // we round to nearest if the difference is small, otherwise upwards
141  static std::ptrdiff_t distance(T from, T to, T step)
142  {
143  const double diff = (double(to) - double(from)) / double(step);
144  return diff > 0.0
145  ? (std::ptrdiff_t)std::ceil(diff*(1.0-2.0*limit::epsilon()))
146  : (std::ptrdiff_t)std::floor(diff*(1.0-2.0*limit::epsilon()));
147  }
148 };
149 
150 } // namespace detail
151 
152 /** \addtogroup RangesAndPoints
153 */
154 //@{
155 
156  /** \brief Iterator that counts upwards or downwards with a given step size.
157 
158  This iterator replicates the functionality of Python's
159  well-known range-function. It is especially convenient in
160  range-based for-loops. <tt>CountingIterator</tt> also works for
161  floating-point counting.
162 
163  <b>Usage:</b>
164 
165  <b>\#include</b> <vigra/counting_iterator.hxx><br>
166  Namespace: vigra
167 
168  You will normally construct instances of this iterator with
169  one of the <tt>range()</tt> factory functions. There are three versions
170  of this function <tt>range(end)</tt>, <tt>range(begin, end)</tt>, and
171  <tt>range(begin, end, step)</tt>.
172  \code
173  // count upwards from 0 to 4
174  for(int i: range(5))
175  std::cout << i << " "; // prints '0 1 2 3 4'
176 
177  // count upwards from 4 to 7
178  for(int i: range(4, 8))
179  std::cout << i << " "; // prints '4 5 6 7'
180 
181  // count upwards from 0 to 9 with step 3
182  for(int i: range(0, 9, 3))
183  std::cout << i << " "; // prints '0 3 6'
184 
185  // likewise (note upper bound)
186  for(int i: range(0, 7, 3))
187  std::cout << i << " "; // prints '0 3 6'
188 
189  // count downwards from 4 to 1 with step -1
190  for(int i: range(4, 0))
191  std::cout << i << " "; // prints '4 3 2 1'
192 
193  // count downwards from 8 to 2 with step -2
194  for(int i: range(8, 0, -2))
195  std::cout << i << " "; // prints '8 6 4 2'
196  \endcode
197 
198  Alternatively, you can create a traditional random-access iterator pair.
199  The end iterator can be conveniently constructed by the begin iterator's
200  <tt>end()</tt> function:
201  \code
202  auto iter = range(5),
203  end = iter.end();
204  std::cout << std::accumulate(iter, end, 0) << std::endl; // prints '10'
205  \endcode
206 
207  <tt>range()</tt> and <tt>CountingIterator</tt> also work for floating-point
208  arguments. As in the integer case, the upper bound is excluded from the range
209  if it can be reached by an integer multiple of the step (within machine
210  epsilon):
211  \code
212  for(auto i: range(1.0, 1.6, 0.1)) // 1.6 is excluded
213  std::cout << i << " "; // prints '1 1.1 1.2 1.3 1.4 1.5'
214 
215  for(auto i: range(1.0, 1.61, 0.1)) // 1.6 is included
216  std::cout << i << " "; // prints '1 1.1 1.2 1.3 1.4 1.5 1.6'
217  \endcode
218 
219  If you use an iterator pair, you can make clear which behavior you want
220  by using either <tt>iter < end</tt> or <tt>iter <= end</tt> to terminate
221  the loop:
222  \code
223  auto iter = range(1.0, 1.6, 0.1),
224  end = iter.end();
225  for(; iter < end; ++iter) // exclude upper bound
226  std::cout << *iter << " "; // prints '1 1.1 1.2 1.3 1.4 1.5'
227 
228  iter = range(1.0, 1.6, 0.1);
229  for(; iter <= end; ++iter) // include upper bound
230  std::cout << *iter << " "; // prints '1 1.1 1.2 1.3 1.4 1.5 1.6'
231  \endcode
232 
233  Note that the termination condition is still <tt>iter <= end</tt>, even
234  when the iterator counts downwards:
235  \code
236  auto iter = range(1.6, 1.0, -0.1),
237  end = iter.end();
238  for(; iter <= end; ++iter)
239  std::cout << *iter << " "; // prints '1.6 1.5 1.4 1.3 1.2 1.1 1'
240  \endcode
241  */
242 template<class T = std::ptrdiff_t>
244 : public std::iterator<std::random_access_iterator_tag,
245  T, std::ptrdiff_t, T const *, T>
246 {
247  public:
249  : begin_(0)
250  , end_(0)
251  , step_(1)
252  {}
253 
254  CountingIterator(T begin, T end)
255  : begin_(begin)
256  , end_(end)
257  , step_(1)
258  {
259  vigra_precondition(begin <= end,
260  "CountingIterator(): begin must be less or equal to end.");
261  }
262 
263  CountingIterator(T begin, T end, T step)
264  : begin_(begin)
265  , end_(end)
266  , step_(step)
267  {
268  vigra_precondition(step != 0,
269  "CountingIterator(): step must be non-zero.");
270  vigra_precondition((step > 0 && begin <= end) || (step < 0 && begin >= end),
271  "CountingIterator(): sign mismatch between step and (end-begin).");
272  }
273 
274  CountingIterator(CountingIterator const & other, ReverseCopyTag)
275  : begin_(other.end_)
276  , end_(other.begin_)
277  , step_(-other.step_)
278  {}
279 
280  public:
281 
282  CountingIterator begin() const
283  {
284  return *this;
285  }
286 
287  CountingIterator end() const
288  {
289  // since the range-based for-loop checks "iter != end",
290  // (end - begin) must be a multiple of step to avoid infinite loops
291  T end = begin_ + step_*Compare::distance(begin_, end_, step_);
292  return CountingIterator(end, end, step_);
293  }
294 
295  bool empty() const
296  {
297  return Compare::greater_equal(begin_, end_, step_);
298  }
299 
300  CountingIterator& operator++() {begin_ += step_; return *this;} // prefix++
301  CountingIterator operator++(int) {CountingIterator tmp(*this); ++(*this); return tmp;} // postfix++
302  CountingIterator& operator--() {begin_ -= step_; return *this;} // prefix--
303  CountingIterator operator--(int) {CountingIterator tmp(*this); --(*this); return tmp;} // postfix--
304 
305  CountingIterator& operator+=(std::ptrdiff_t n)
306  {
307  begin_ += n*step_;
308  return *this;
309  }
310 
311  CountingIterator operator+(std::ptrdiff_t n) const
312  {
313  return CountingIterator(*this) += n;
314  }
315 
316  CountingIterator& operator-=(std::ptrdiff_t n)
317  {
318  begin_ -= n*step_;
319  return *this;
320  }
321 
322  CountingIterator operator-(std::ptrdiff_t n) const
323  {
324  return CountingIterator(*this) -= n;
325  }
326 
327  std::ptrdiff_t operator-(const CountingIterator& other) const
328  {
329  return Compare::distance(other.begin_, begin_, step_);
330  }
331 
332  bool operator<(CountingIterator const & other) const
333  {
334  return Compare::less(begin_, other.begin_, step_);
335  }
336 
337  bool operator<=(CountingIterator const & other) const
338  {
339  return Compare::less_equal(begin_, other.begin_, step_);
340  }
341 
342  bool operator>(CountingIterator const & other) const
343  {
344  return Compare::greater(begin_, other.begin_, step_);
345  }
346 
347  bool operator>=(CountingIterator const & other) const
348  {
349  return Compare::greater_equal(begin_, other.begin_, step_);
350  }
351 
352  bool operator==(const CountingIterator& other) const
353  {
354  return Compare::equal(begin_, other.begin_, step_);
355  }
356 
357  bool operator!=(const CountingIterator& other) const
358  {
359  return Compare::not_equal(begin_, other.begin_, step_);
360  }
361 
362  T operator[](std::ptrdiff_t n) const {
363  return begin_ + n*step_;
364  }
365 
366  T operator*() const {
367  return begin_;
368  }
369 
370  T const * operator->() const{
371  return &begin_;
372  }
373 
374  private:
375 
376  typedef detail::CountingIteratorCompare<T, std::is_floating_point<T>::value> Compare;
377 
378  T begin_, end_, step_;
379 };
380 
381 
382 template <class T1, class T2, class T3>
384 range(T1 begin, T2 end, T3 step)
385 {
386  return CountingIterator<T1>(begin, end, step);
387 }
388 
389 template <class T1, class T2>
390 inline CountingIterator<T1>
391 range(T1 begin, T2 end)
392 {
393  return CountingIterator<T1>(begin, end, 1);
394 }
395 
396 template <class T>
397 inline CountingIterator<T>
398 range(T end)
399 {
400  return CountingIterator<T>(0, end, 1);
401 }
402 
403 //@}
404 
405 } // namespace vigra
406 
407 #endif
Iterator that counts upwards or downwards with a given step size.
Definition: counting_iterator.hxx:243
int ceil(FixedPoint< IntBits, FracBits > v)
rounding up.
Definition: fixedpoint.hxx:675
int floor(FixedPoint< IntBits, FracBits > v)
rounding down.
Definition: fixedpoint.hxx:667

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.11.1 (Fri May 19 2017)