ITK  5.0.0
Insight Segmentation and Registration Toolkit
itkIndexRange.h
Go to the documentation of this file.
1 /*=========================================================================
2 *
3 * Copyright Insight Software Consortium
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18 
19 #ifndef itkIndexRange_h
20 #define itkIndexRange_h
21 
22 #include <cassert>
23 #include <cstddef> // For ptrdiff_t.
24 #include <iterator> // For bidirectional_iterator_tag and reverse_iterator.
25 #include <type_traits> // For conditional and enable_if.
26 
27 #include "itkImageRegion.h"
28 #include "itkIndex.h"
29 #include "itkSize.h"
30 
31 namespace itk
32 {
33 namespace Experimental
34 {
35 
79 template<unsigned VDimension, bool VBeginAtZero>
80 class IndexRange final
81 {
82 public:
83  constexpr static unsigned Dimension = VDimension;
86 
87  class const_iterator final
88  {
89  public:
90  // Types conforming the iterator requirements of the C++ standard library:
91  using difference_type = std::ptrdiff_t;
93  using reference = const IndexType&;
94  using pointer = const IndexType*;
95  using iterator_category = std::bidirectional_iterator_tag;
96 
102  const_iterator() = default;
103 
104 
106  reference operator*() const ITK_NOEXCEPT
107  {
108  return m_Index;
109  }
110 
111 
113  pointer operator->() const ITK_NOEXCEPT
114  {
115  return &(**this);
116  }
117 
118 
120  const_iterator& operator++() ITK_NOEXCEPT
121  {
122  for (unsigned i = 0; i < (VDimension - 1); ++i)
123  {
124  auto& indexValue = m_Index[i];
126 
127  ++indexValue;
128 
129  if (indexValue <= m_MaxIndex[i])
130  {
131  return *this;
132  }
133  indexValue = m_MinIndex[i];
134  }
135  ++m_Index.back();
136 
137  return *this;
138  }
139 
140 
143  const_iterator operator++(int) ITK_NOEXCEPT
144  {
145  auto result = *this;
146  ++(*this);
147  return result;
148  }
150 
151 
153  const_iterator& operator--() ITK_NOEXCEPT
154  {
155  for (unsigned i = 0; i < (VDimension - 1); ++i)
156  {
157  auto& indexValue = m_Index[i];
159 
160  --indexValue;
161 
162  if (indexValue >= m_MinIndex[i])
163  {
164  return *this;
165  }
166  indexValue = m_MaxIndex[i];
167  }
168  --m_Index.back();
169  return *this;
170  }
171 
172 
175  const_iterator operator--(int) ITK_NOEXCEPT
176  {
177  auto result = *this;
178  --(*this);
179  return result;
180  }
182 
183 
187  friend bool operator==(const const_iterator& lhs, const const_iterator& rhs) ITK_NOEXCEPT
188  {
189  assert(lhs.m_MaxIndex == rhs.m_MaxIndex);
190 
191  return lhs.m_Index == rhs.m_Index;
192  }
193 
194 
196  friend bool operator!=(const const_iterator& lhs, const const_iterator& rhs) ITK_NOEXCEPT
197  {
198  // Implemented just like the corresponding std::rel_ops operator.
199  return !(lhs == rhs);
200  }
201 
202 
204  friend bool operator<(const const_iterator& lhs, const const_iterator& rhs) ITK_NOEXCEPT
205  {
206  for (unsigned i = VDimension; i > 0; --i)
207  {
208  const auto difference = lhs.m_Index[i - 1] - rhs.m_Index[i - 1];
210 
211  if (difference < 0)
212  {
213  return true;
214  }
215  if (difference > 0)
216  {
217  break;
218  }
219  }
220  return false;
221  }
222 
223 
225  friend bool operator>(const const_iterator& lhs, const const_iterator& rhs) ITK_NOEXCEPT
226  {
227  // Implemented just like the corresponding std::rel_ops operator.
228  return rhs < lhs;
229  }
230 
231 
233  friend bool operator<=(const const_iterator& lhs, const const_iterator& rhs) ITK_NOEXCEPT
234  {
235  // Implemented just like the corresponding std::rel_ops operator.
236  return !(rhs < lhs);
237  }
238 
239 
241  friend bool operator>=(const const_iterator& lhs, const const_iterator& rhs) ITK_NOEXCEPT
242  {
243  // Implemented just like the corresponding std::rel_ops operator.
244  return !(lhs < rhs);
245  }
246 
247 
248  private:
249  friend class IndexRange;
250 
251  // Represents an N-dimensional index that is always zero
252  // Aims towards zero runtime overhead.
253  struct ZeroIndex
254  {
255  // The "index" operator.
256  constexpr IndexValueType operator[](unsigned) const
257  {
258  return 0;
259  }
260 
261  // Implicitly converts to a default-initialized itk::Index<N>.
262  constexpr operator IndexType() const
263  {
264  return IndexType();
265  }
266  };
267 
268 
269  // When BeginAtZero is true, use zero as minimum index, otherwise use itk::Index<N>.
270  using MinIndexType = typename std::conditional<VBeginAtZero, ZeroIndex, IndexType>::type;
271 
272  // Private constructor, only used by friend class IndexRange.
274  const IndexType& index,
275  const MinIndexType& minIndex,
276  const IndexType& maxIndex) ITK_NOEXCEPT
277  :
278  // Note: Use parentheses instead of curly braces to initialize data members,
279  // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
280  m_Index(index),
281  m_MinIndex(minIndex),
282  m_MaxIndex(maxIndex)
283  {
284  }
285 
286 
287  // IndexRange::const_iterator data members:
288 
289  // Current (N-dimensional) index.
291 
292  // Minimum (N-dimensional) index.
294 
295  // Maximum (N-dimensional) index.
297  };
298 
300  using reverse_iterator = std::reverse_iterator<iterator>;
301  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
302 
308  IndexRange() ITK_NOEXCEPT
309  :
310  m_MinIndex(),
311  m_MaxIndex()
312  {
313  // m_MinIndex and m_MaxIndex are "inclusive" boundaries of the index, so
314  // in order to construct an empty range, m_MaxIndex must take one step back.
315  m_MaxIndex.back() = -1;
316  }
317 
318 
321  explicit IndexRange(const SizeType& gridSize)
322  :
323  // Note: Use parentheses instead of curly braces to initialize data members,
324  // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
325  m_MinIndex(),
326  m_MaxIndex(CalculateMaxIndex(typename iterator::MinIndexType(), gridSize))
327  {
328  }
329 
330 
335  template <bool VIsSubstitutionFailure = VBeginAtZero,
336  typename TVoid = typename std::enable_if<!VIsSubstitutionFailure>::type>
337  explicit IndexRange(const ImageRegion<VDimension>& imageRegion)
338  :
339  // Note: Use parentheses instead of curly braces to initialize data members,
340  // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
341  m_MinIndex(imageRegion.GetIndex()),
342  m_MaxIndex(CalculateMaxIndex(imageRegion.GetIndex(), imageRegion.GetSize()))
343  {
344  // Three compile-time asserts, just to check if SFINAE worked properly:
345  static_assert(!VIsSubstitutionFailure,
346  "This template should (of course) be instantiated without substitution failure.");
347  static_assert(std::is_same<TVoid, void>::value,
348  "std::enable_if<!VIsSubstitutionFailure> should yield void, by definition.");
349  static_assert(!VBeginAtZero,
350  "This constructor should only be is available when VBeginAtZero is false.");
351  }
353 
354 
356  iterator begin() const ITK_NOEXCEPT
357  {
359  }
360 
362  iterator end() const ITK_NOEXCEPT
363  {
364  IndexType index = m_MinIndex;
365  index.back() = m_MaxIndex.back() + 1;
366  return iterator(index, m_MinIndex, m_MaxIndex);
367  }
369 
372  const_iterator cbegin() const ITK_NOEXCEPT
373  {
374  return this->begin();
375  }
376 
378  const_iterator cend() const ITK_NOEXCEPT
379  {
380  return this->end();
381  }
382 
384  reverse_iterator rbegin() const ITK_NOEXCEPT
385  {
386  return reverse_iterator(this->end());
387  }
388 
390  reverse_iterator rend() const ITK_NOEXCEPT
391  {
392  return reverse_iterator(this->begin());
393  }
394 
396  const_reverse_iterator crbegin() const ITK_NOEXCEPT
397  {
398  return this->rbegin();
399  }
400 
402  const_reverse_iterator crend() const ITK_NOEXCEPT
403  {
404  return this->rend();
405  }
406 
407 
409  std::size_t size() const ITK_NOEXCEPT
410  {
411  std::size_t result = 1;
412 
413  for (unsigned i = 0; i < VDimension; ++i)
414  {
415  result *= ((m_MaxIndex[i] + 1) - m_MinIndex[i]);
416  }
417  return result;
418  }
419 
420 
422  bool empty() const ITK_NOEXCEPT
423  {
424  for (unsigned i = 0; i < VDimension; ++i)
425  {
426  if (m_MaxIndex[i] == (m_MinIndex[i] - 1))
427  {
428  return true;
429  }
430  }
431  return false;
432  }
434 
435 
436 private:
437 
439 
440  static IndexType CalculateMaxIndex(const MinIndexType& minIndex, const SizeType& size)
441  {
442  IndexType index;
443 
444  for (unsigned i = 0; i < VDimension; ++i)
445  {
446  index[i] = minIndex[i] + static_cast<IndexValueType>(size[i]) - 1;
447  }
448 
449  return index;
450  }
451 
452  // IndexRange data members:
453 
454  // Minimum (N-dimensional) index.
456 
457  // Maximum (N-dimensional) index.
459 
460 };
461 
462 template<unsigned VDimension>
464 
465 template<unsigned VDimension>
467 
468 } // namespace Experimental
469 } // namespace itk
470 
471 #endif
std::reverse_iterator< const_iterator > const_reverse_iterator
IndexRange(const SizeType &gridSize)
constexpr IndexValueType operator[](unsigned) const
Represent a n-dimensional index in a n-dimensional image.
Definition: itkIndex.h:66
const_iterator cend() const noexcept
const_iterator(const IndexType &index, const MinIndexType &minIndex, const IndexType &maxIndex) noexcept
friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) noexcept
reverse_iterator rend() const noexcept
bool empty() const noexcept
friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs) noexcept
typename std::conditional< VBeginAtZero, ZeroIndex, IndexType >::type MinIndexType
iterator end() const noexcept
Index< VDimension > IndexType
Definition: itkIndexRange.h:85
const_reverse_iterator crbegin() const noexcept
friend bool operator<(const const_iterator &lhs, const const_iterator &rhs) noexcept
iterator begin() const noexcept
const_iterator cbegin() const noexcept
std::reverse_iterator< iterator > reverse_iterator
reference back()
Definition: itkIndex.h:423
friend bool operator>(const const_iterator &lhs, const const_iterator &rhs) noexcept
std::bidirectional_iterator_tag iterator_category
Definition: itkIndexRange.h:95
signed long IndexValueType
Definition: itkIntTypes.h:90
Represent a n-dimensional size (bounds) of a n-dimensional image.
Definition: itkSize.h:68
typename iterator::MinIndexType MinIndexType
const_iterator operator++(int) noexcept
std::vcl_size_t size() const noexcept
friend bool operator>=(const const_iterator &lhs, const const_iterator &rhs) noexcept
reverse_iterator rbegin() const noexcept
static IndexType CalculateMaxIndex(const MinIndexType &minIndex, const SizeType &size)
IndexRange(const ImageRegion< VDimension > &imageRegion)
friend bool operator<=(const const_iterator &lhs, const const_iterator &rhs) noexcept
const_iterator operator--(int) noexcept
const_reverse_iterator crend() const noexcept
static constexpr unsigned Dimension
Definition: itkIndexRange.h:83