ITK  5.4.0
Insight Toolkit
itkIndexRange.h
Go to the documentation of this file.
1/*=========================================================================
2 *
3 * Copyright NumFOCUS
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 * https://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
31namespace itk
32{
33
77template <unsigned int VDimension, bool VBeginAtZero>
78class IndexRange final
79{
80public:
81 static constexpr unsigned int Dimension = VDimension;
84
85 class const_iterator final
86 {
87 public:
88 // Types conforming the iterator requirements of the C++ standard library:
89 using difference_type = ptrdiff_t;
91 using reference = const IndexType &;
92 using pointer = const IndexType *;
93 using iterator_category = std::bidirectional_iterator_tag;
94
100 const_iterator() = default;
101
102
104 reference operator*() const noexcept { return m_Index; }
105
106
108 pointer operator->() const noexcept { return &(**this); }
109
110
113 operator++() noexcept
114 {
115 for (unsigned int i = 0; i < (VDimension - 1); ++i)
116 {
117 auto & indexValue = m_Index[i];
120 ++indexValue;
121
122 if (indexValue <= m_MaxIndex[i])
123 {
124 return *this;
125 }
126 indexValue = m_MinIndex[i];
127 }
128 ++m_Index.back();
129
130 return *this;
131 }
132
133
137 operator++(int) noexcept
138 {
139 auto result = *this;
140 ++(*this);
141 return result;
142 }
148 operator--() noexcept
149 {
150 for (unsigned int i = 0; i < (VDimension - 1); ++i)
151 {
152 auto & indexValue = m_Index[i];
155 --indexValue;
156
157 if (indexValue >= m_MinIndex[i])
158 {
159 return *this;
160 }
161 indexValue = m_MaxIndex[i];
162 }
163 --m_Index.back();
164 return *this;
165 }
166
167
171 operator--(int) noexcept
172 {
173 auto result = *this;
174 --(*this);
175 return result;
176 }
183 friend bool
184 operator==(const const_iterator & lhs, const const_iterator & rhs) noexcept
185 {
186 assert(lhs.m_MaxIndex == rhs.m_MaxIndex);
187
188 return lhs.m_Index == rhs.m_Index;
189 }
190
191
193 friend bool
194 operator!=(const const_iterator & lhs, const const_iterator & rhs) noexcept
195 {
196 // Implemented just like the corresponding std::rel_ops operator.
197 return !(lhs == rhs);
198 }
199
200
202 friend bool
203 operator<(const const_iterator & lhs, const const_iterator & rhs) noexcept
204 {
205 for (unsigned int i = VDimension; i > 0; --i)
206 {
207 const auto difference = lhs.m_Index[i - 1] - rhs.m_Index[i - 1];
210 if (difference < 0)
211 {
212 return true;
213 }
214 if (difference > 0)
215 {
216 break;
217 }
218 }
219 return false;
220 }
221
222
224 friend bool
225 operator>(const const_iterator & lhs, const const_iterator & rhs) noexcept
226 {
227 // Implemented just like the corresponding std::rel_ops operator.
228 return rhs < lhs;
229 }
230
231
233 friend bool
234 operator<=(const const_iterator & lhs, const const_iterator & rhs) noexcept
235 {
236 // Implemented just like the corresponding std::rel_ops operator.
237 return !(rhs < lhs);
238 }
239
240
242 friend bool
243 operator>=(const const_iterator & lhs, const const_iterator & rhs) noexcept
244 {
245 // Implemented just like the corresponding std::rel_ops operator.
246 return !(lhs < rhs);
247 }
248
249
250 private:
251 friend class IndexRange;
252
253 // Represents an N-dimensional index that is always zero
254 // Aims towards zero runtime overhead.
256 {
257 // The "index" operator.
258 constexpr IndexValueType operator[](unsigned int) const { return 0; }
259
260 // Implicitly converts to a default-initialized itk::Index<N>.
261 constexpr operator IndexType() const { return IndexType(); }
262 };
263
264
265 // When BeginAtZero is true, use zero as minimum index, otherwise use itk::Index<N>.
266 using MinIndexType = std::conditional_t<VBeginAtZero, ZeroIndex, IndexType>;
267
268 // Private constructor, only used by friend class IndexRange.
269 const_iterator(const IndexType & index, const MinIndexType & minIndex, const IndexType & maxIndex) noexcept
270 : // Note: Use parentheses instead of curly braces to initialize data members,
271 // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
272 m_Index(index)
273 , m_MinIndex(minIndex)
274 , m_MaxIndex(maxIndex)
275 {}
276
277
278 // IndexRange::const_iterator data members:
279
280 // Current (N-dimensional) index.
282
283 // Minimum (N-dimensional) index.
285
286 // Maximum (N-dimensional) index.
288 };
289
291 using reverse_iterator = std::reverse_iterator<iterator>;
292 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
293
299 IndexRange() = default;
300
301
304 explicit IndexRange(const SizeType & gridSize)
305 : // Note: Use parentheses instead of curly braces to initialize data members,
306 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
307 m_MinIndex()
308 , m_MaxIndex(CalculateMaxIndex(typename iterator::MinIndexType(), gridSize))
309 {}
310
311
316 template <bool VIsSubstitutionFailure = VBeginAtZero,
317 typename TVoid = std::enable_if_t<!VIsSubstitutionFailure>>
318 explicit IndexRange(const ImageRegion<VDimension> & imageRegion)
319 : // Note: Use parentheses instead of curly braces to initialize data members,
320 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
321 m_MinIndex(imageRegion.GetIndex())
322 , m_MaxIndex(CalculateMaxIndex(imageRegion.GetIndex(), imageRegion.GetSize()))
323 {
324 // Three compile-time asserts, just to check if SFINAE worked properly:
325 static_assert(!VIsSubstitutionFailure,
326 "This template should (of course) be instantiated without substitution failure.");
327 static_assert(std::is_same_v<TVoid, void>,
328 "std::enable_if<!VIsSubstitutionFailure> should yield void, by definition.");
329 static_assert(!VBeginAtZero, "This constructor should only be is available when VBeginAtZero is false.");
330 }
336 begin() const noexcept
337 {
339 }
340
343 end() const noexcept
344 {
345 IndexType index = m_MinIndex;
346 index.back() = m_MaxIndex.back() + 1;
347 return iterator(index, m_MinIndex, m_MaxIndex);
348 }
353 const_iterator
354 cbegin() const noexcept
355 {
356 return this->begin();
357 }
358
360 const_iterator
361 cend() const noexcept
362 {
363 return this->end();
364 }
365
368 rbegin() const noexcept
369 {
370 return reverse_iterator(this->end());
371 }
372
375 rend() const noexcept
376 {
377 return reverse_iterator(this->begin());
378 }
379
382 crbegin() const noexcept
383 {
384 return this->rbegin();
385 }
386
389 crend() const noexcept
390 {
391 return this->rend();
392 }
393
394
396 size_t
397 size() const noexcept
398 {
399 size_t result = 1;
400
401 for (unsigned int i = 0; i < VDimension; ++i)
402 {
403 result *= ((m_MaxIndex[i] + 1) - m_MinIndex[i]);
404 }
405 return result;
406 }
407
408
410 bool
411 empty() const noexcept
412 {
413 // When an IndexRange is empty, each index value of m_MaxIndex is less than the corresponding
414 // index value of m_MinIndex. And vice versa: when an IndexRange is non-empty, each index value
415 // of m_MaxIndex is greater than or equal to the corresponding index value of m_MinIndex.
416 // Note that the range contains one element when m_MaxIndex == m_MinIndex.
417 return m_MaxIndex[0] < m_MinIndex[0];
418 }
419
420
421private:
423
424 static IndexType
425 CalculateMaxIndex(const MinIndexType & minIndex, const SizeType & size)
426 {
427 const bool sizeHasZeroValue = [&size] {
428 for (const auto sizeValue : size)
429 {
430 if (sizeValue == 0)
431 {
432 return true;
433 }
434 }
435 return false;
436 }();
437
438 // Treat any size that has a zero value equally.
439 const SizeType normalizedSize = sizeHasZeroValue ? SizeType{ { 0 } } : size;
440
441 IndexType index;
442
443 for (unsigned int i = 0; i < VDimension; ++i)
444 {
445 index[i] = minIndex[i] + static_cast<IndexValueType>(normalizedSize[i]) - 1;
446 }
447
448 return index;
449 }
450
451 // IndexRange data members:
452
453 // Minimum (N-dimensional) index.
455
456 // Maximum (N-dimensional) index.
458};
459
460template <unsigned int VDimension>
462
463template <unsigned int VDimension>
465
466} // namespace itk
467
468#endif
friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs) noexcept
reference operator*() const noexcept
friend bool operator>=(const const_iterator &lhs, const const_iterator &rhs) noexcept
friend bool operator<=(const const_iterator &lhs, const const_iterator &rhs) noexcept
std::bidirectional_iterator_tag iterator_category
Definition: itkIndexRange.h:93
pointer operator->() const noexcept
friend bool operator>(const const_iterator &lhs, const const_iterator &rhs) noexcept
const_iterator & operator--() noexcept
const_iterator operator++(int) noexcept
const_iterator operator--(int) noexcept
friend bool operator<(const const_iterator &lhs, const const_iterator &rhs) noexcept
friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) noexcept
const_iterator & operator++() noexcept
std::conditional_t< VBeginAtZero, ZeroIndex, IndexType > MinIndexType
const_iterator(const IndexType &index, const MinIndexType &minIndex, const IndexType &maxIndex) noexcept
const_iterator cend() const noexcept
const_reverse_iterator crend() const noexcept
Index< VDimension > IndexType
Definition: itkIndexRange.h:83
std::reverse_iterator< const_iterator > const_reverse_iterator
MinIndexType m_MinIndex
typename iterator::MinIndexType MinIndexType
const_reverse_iterator crbegin() const noexcept
static IndexType CalculateMaxIndex(const MinIndexType &minIndex, const SizeType &size)
vcl_size_t size() const noexcept
IndexRange(const ImageRegion< VDimension > &imageRegion)
std::reverse_iterator< iterator > reverse_iterator
static constexpr unsigned int Dimension
Definition: itkIndexRange.h:81
iterator end() const noexcept
const_iterator iterator
reverse_iterator rbegin() const noexcept
const_iterator cbegin() const noexcept
IndexType m_MaxIndex
reverse_iterator rend() const noexcept
iterator begin() const noexcept
IndexRange(const SizeType &gridSize)
IndexRange()=default
bool empty() const noexcept
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
long IndexValueType
Definition: itkIntTypes.h:90
constexpr IndexValueType operator[](unsigned int) const
static constexpr Self Filled(const IndexValueType value)
Definition: itkIndex.h:496
reference back()
Definition: itkIndex.h:469