ITK  6.0.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 constexpr reference operator*() const noexcept { return m_Index; }
105
106
108 constexpr pointer operator->() const noexcept { return &(**this); }
109
110
112 constexpr const_iterator &
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
136 constexpr const_iterator
137 operator++(int) noexcept
138 {
139 auto result = *this;
140 ++(*this);
141 return result;
142 }
147 constexpr const_iterator &
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
170 constexpr const_iterator
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 constexpr 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 constexpr 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 constexpr 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 constexpr 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 constexpr const_iterator(const IndexType & index,
270 const MinIndexType & minIndex,
271 const IndexType & maxIndex) noexcept
272 : // Note: Use parentheses instead of curly braces to initialize data members,
273 // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
274 m_Index(index)
275 , m_MinIndex(minIndex)
276 , m_MaxIndex(maxIndex)
277 {}
278
279
280 // IndexRange::const_iterator data members:
281
282 // Current (N-dimensional) index.
284
285 // Minimum (N-dimensional) index.
287
288 // Maximum (N-dimensional) index.
290 };
291
293 using reverse_iterator = std::reverse_iterator<iterator>;
294 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
295
301 IndexRange() = default;
302
303
306 constexpr explicit IndexRange(const SizeType & gridSize)
307 : // Note: Use parentheses instead of curly braces to initialize data members,
308 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
309 m_MinIndex()
310 , m_MaxIndex(CalculateMaxIndex(typename iterator::MinIndexType(), gridSize))
311 {}
312
313
318 template <bool VIsSubstitutionFailure = VBeginAtZero,
319 typename TVoid = std::enable_if_t<!VIsSubstitutionFailure>>
320 explicit IndexRange(const ImageRegion<VDimension> & imageRegion)
321 : // Note: Use parentheses instead of curly braces to initialize data members,
322 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
323 m_MinIndex(imageRegion.GetIndex())
324 , m_MaxIndex(CalculateMaxIndex(imageRegion.GetIndex(), imageRegion.GetSize()))
325 {
326 // Three compile-time asserts, just to check if SFINAE worked properly:
327 static_assert(!VIsSubstitutionFailure,
328 "This template should (of course) be instantiated without substitution failure.");
329 static_assert(std::is_same_v<TVoid, void>,
330 "std::enable_if<!VIsSubstitutionFailure> should yield void, by definition.");
331 static_assert(!VBeginAtZero, "This constructor should only be is available when VBeginAtZero is false.");
332 }
337 constexpr iterator
338 begin() const noexcept
339 {
341 }
342
344 constexpr iterator
345 end() const noexcept
346 {
347 IndexType index = m_MinIndex;
348 index.back() = m_MaxIndex.back() + 1;
349 return iterator(index, m_MinIndex, m_MaxIndex);
350 }
355 constexpr const_iterator
356 cbegin() const noexcept
357 {
358 return this->begin();
359 }
360
362 constexpr const_iterator
363 cend() const noexcept
364 {
365 return this->end();
366 }
367
370 rbegin() const noexcept
371 {
372 return reverse_iterator(this->end());
373 }
374
377 rend() const noexcept
378 {
379 return reverse_iterator(this->begin());
380 }
381
384 crbegin() const noexcept
385 {
386 return this->rbegin();
387 }
388
391 crend() const noexcept
392 {
393 return this->rend();
394 }
395
396
398 constexpr size_t
399 size() const noexcept
400 {
401 size_t result = 1;
402
403 for (unsigned int i = 0; i < VDimension; ++i)
404 {
405 result *= ((m_MaxIndex[i] + 1) - m_MinIndex[i]);
406 }
407 return result;
408 }
409
410
412 constexpr bool
413 empty() const noexcept
414 {
415 // When an IndexRange is empty, each index value of m_MaxIndex is less than the corresponding
416 // index value of m_MinIndex. And vice versa: when an IndexRange is non-empty, each index value
417 // of m_MaxIndex is greater than or equal to the corresponding index value of m_MinIndex.
418 // Note that the range contains one element when m_MaxIndex == m_MinIndex.
419 return m_MaxIndex[0] < m_MinIndex[0];
420 }
421
422
423private:
425
426 static constexpr IndexType
427 CalculateMaxIndex(const MinIndexType & minIndex, const SizeType & size)
428 {
429 const bool sizeHasZeroValue = [&size] {
430 for (const auto sizeValue : size)
431 {
432 if (sizeValue == 0)
433 {
434 return true;
435 }
436 }
437 return false;
438 }();
439
440 // Treat any size that has a zero value equally.
441 const SizeType normalizedSize = sizeHasZeroValue ? SizeType{ { 0 } } : size;
442
443 // The `index` is initialized (`{}`), just to support C++17 constexpr.
444 IndexType index{};
445
446 for (unsigned int i = 0; i < VDimension; ++i)
447 {
448 index[i] = minIndex[i] + static_cast<IndexValueType>(normalizedSize[i]) - 1;
449 }
450
451 return index;
452 }
453
454 // IndexRange data members:
455
456 // Minimum (N-dimensional) index.
458
459 // Maximum (N-dimensional) index.
461};
462
463template <unsigned int VDimension>
465
466template <unsigned int VDimension>
468
469} // namespace itk
470
471#endif
friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs) noexcept
friend constexpr bool operator>=(const const_iterator &lhs, const const_iterator &rhs) noexcept
friend constexpr bool operator<=(const const_iterator &lhs, const const_iterator &rhs) noexcept
constexpr const_iterator & operator--() noexcept
std::bidirectional_iterator_tag iterator_category
Definition: itkIndexRange.h:93
friend constexpr bool operator<(const const_iterator &lhs, const const_iterator &rhs) noexcept
constexpr reference operator*() const noexcept
constexpr pointer operator->() const noexcept
constexpr const_iterator(const IndexType &index, const MinIndexType &minIndex, const IndexType &maxIndex) noexcept
friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) noexcept
std::conditional_t< VBeginAtZero, ZeroIndex, IndexType > MinIndexType
constexpr const_iterator & operator++() noexcept
constexpr const_iterator operator++(int) noexcept
constexpr const_iterator operator--(int) noexcept
friend constexpr bool operator>(const const_iterator &lhs, const const_iterator &rhs) 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
constexpr bool empty() const noexcept
typename iterator::MinIndexType MinIndexType
const_reverse_iterator crbegin() const noexcept
constexpr iterator end() const noexcept
constexpr vcl_size_t size() const noexcept
IndexRange(const ImageRegion< VDimension > &imageRegion)
std::reverse_iterator< iterator > reverse_iterator
static constexpr IndexType CalculateMaxIndex(const MinIndexType &minIndex, const SizeType &size)
constexpr const_iterator cend() const noexcept
static constexpr unsigned int Dimension
Definition: itkIndexRange.h:81
const_iterator iterator
reverse_iterator rbegin() const noexcept
IndexType m_MaxIndex
reverse_iterator rend() const noexcept
constexpr iterator begin() const noexcept
constexpr const_iterator cbegin() const noexcept
constexpr IndexRange(const SizeType &gridSize)
IndexRange()=default
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
long IndexValueType
Definition: itkIntTypes.h:93
constexpr IndexValueType operator[](unsigned int) const
static constexpr Self Filled(const IndexValueType value)
Definition: itkIndex.h:494
constexpr reference back()
Definition: itkIndex.h:467