ITK 6.0.0
Insight Toolkit
 
Loading...
Searching...
No Matches
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
76template <unsigned int VDimension, bool VBeginAtZero>
77class IndexRange final
78{
79public:
80 static constexpr unsigned int Dimension = VDimension;
83
84 class const_iterator final
85 {
86 public:
87 // Types conforming the iterator requirements of the C++ standard library:
88 using difference_type = ptrdiff_t;
90 using reference = const IndexType &;
91 using pointer = const IndexType *;
92 using iterator_category = std::bidirectional_iterator_tag;
93
99 const_iterator() = default;
100
101
103 constexpr reference
104 operator*() const noexcept
105 {
106 return m_Index;
107 }
108
109
111 constexpr pointer
112 operator->() const noexcept
113 {
114 return &(**this);
115 }
116
117
119 constexpr const_iterator &
120 operator++() noexcept
121 {
122 ++m_Position;
123
124 for (unsigned int i = 0; i < (VDimension - 1); ++i)
125 {
126 auto & indexValue = m_Index[i];
127
128 ++indexValue;
129
130 if (indexValue <= m_MaxIndex[i])
131 {
132 return *this;
133 }
134 indexValue = m_MinIndex[i];
135 }
136 ++m_Index.back();
137
138 return *this;
139 }
140
141
144 constexpr const_iterator
145 operator++(int) noexcept
146 {
147 auto result = *this;
148 ++(*this);
149 return result;
150 }
151
152
154 constexpr const_iterator &
155 operator--() noexcept
156 {
157 --m_Position;
158
159 for (unsigned int i = 0; i < (VDimension - 1); ++i)
160 {
161 auto & indexValue = m_Index[i];
162
163 --indexValue;
164
165 if (indexValue >= m_MinIndex[i])
166 {
167 return *this;
168 }
169 indexValue = m_MaxIndex[i];
170 }
171 --m_Index.back();
172 return *this;
173 }
174
175
178 constexpr const_iterator
179 operator--(int) noexcept
180 {
181 auto result = *this;
182 --(*this);
183 return result;
184 }
185
186
190 friend bool
191 operator==(const const_iterator & lhs, const const_iterator & rhs) noexcept
192 {
193 assert(lhs.m_MaxIndex == rhs.m_MaxIndex);
194
195 // Note that comparing m_Position is typically much faster than comparing m_Index, because m_Position is just an
196 // integer, whereas m_Index is of a user-defined type, which usually has more bytes than m_Position.
197 return lhs.m_Position == rhs.m_Position;
198 }
199
200
202 friend bool
203 operator!=(const const_iterator & lhs, const const_iterator & rhs) noexcept
204 {
205 // Implemented just like the corresponding std::rel_ops operator.
206 return !(lhs == rhs);
207 }
208
209
211 friend constexpr bool
212 operator<(const const_iterator & lhs, const const_iterator & rhs) noexcept
213 {
214 return lhs.m_Position < rhs.m_Position;
215 }
216
217
219 friend constexpr bool
220 operator>(const const_iterator & lhs, const const_iterator & rhs) noexcept
221 {
222 // Implemented just like the corresponding std::rel_ops operator.
223 return rhs < lhs;
224 }
225
226
228 friend constexpr bool
229 operator<=(const const_iterator & lhs, const const_iterator & rhs) noexcept
230 {
231 // Implemented just like the corresponding std::rel_ops operator.
232 return !(rhs < lhs);
233 }
234
235
237 friend constexpr bool
238 operator>=(const const_iterator & lhs, const const_iterator & rhs) noexcept
239 {
240 // Implemented just like the corresponding std::rel_ops operator.
241 return !(lhs < rhs);
242 }
243
244
245 private:
246 friend class IndexRange;
247
248 // Represents an N-dimensional index that is always zero
249 // Aims towards zero runtime overhead.
251 {
252 // The "index" operator.
253 constexpr IndexValueType
254 operator[](unsigned int) const
255 {
256 return 0;
257 }
258
259 // Implicitly converts to a default-initialized itk::Index<N>.
260 constexpr
261 operator IndexType() const
262 {
263 return IndexType();
264 }
265 };
266
267
268 // When BeginAtZero is true, use zero as minimum index, otherwise use itk::Index<N>.
269 using MinIndexType = std::conditional_t<VBeginAtZero, ZeroIndex, IndexType>;
270
271 // Private constructor, only used by friend class IndexRange.
272 constexpr const_iterator(const IndexType & index,
273 const MinIndexType & minIndex,
274 const IndexType & maxIndex,
275 const size_t position) noexcept
276 : // Note: Use parentheses instead of curly braces to initialize data members,
277 // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
278 m_Index(index)
279 , m_MinIndex(minIndex)
280 , m_MaxIndex(maxIndex)
281 , m_Position(position)
282 {}
283
284
285 // IndexRange::const_iterator data members:
286
287 // Current (N-dimensional) index.
289
290 // Minimum (N-dimensional) index.
292
293 // Maximum (N-dimensional) index.
295
296 // The position within the range, relative to the begin. So it is zero at the begin, and it is equal to
297 // `range.size()` at the end of the range.
298 size_t m_Position{};
299 };
300
302 using reverse_iterator = std::reverse_iterator<iterator>;
303 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
304
310 IndexRange() = default;
311
312
315 constexpr explicit IndexRange(const SizeType & gridSize)
316 : // Note: Use parentheses instead of curly braces to initialize data members,
317 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
318 m_MinIndex()
319 , m_MaxIndex(CalculateMaxIndex(typename iterator::MinIndexType(), gridSize))
320 {}
321
322
327 template <bool VIsSubstitutionFailure = VBeginAtZero,
328 typename TVoid = std::enable_if_t<!VIsSubstitutionFailure>>
329 explicit IndexRange(const ImageRegion<VDimension> & imageRegion)
330 : // Note: Use parentheses instead of curly braces to initialize data members,
331 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
332 m_MinIndex(imageRegion.GetIndex())
333 , m_MaxIndex(CalculateMaxIndex(imageRegion.GetIndex(), imageRegion.GetSize()))
334 {
335 // Three compile-time asserts, just to check if SFINAE worked properly:
336 static_assert(!VIsSubstitutionFailure,
337 "This template should (of course) be instantiated without substitution failure.");
338 static_assert(std::is_same_v<TVoid, void>,
339 "std::enable_if<!VIsSubstitutionFailure> should yield void, by definition.");
340 static_assert(!VBeginAtZero, "This constructor should only be is available when VBeginAtZero is false.");
341 }
342
343
345 [[nodiscard]] constexpr iterator
346 begin() const noexcept
347 {
349 }
350
352 [[nodiscard]] constexpr iterator
353 end() const noexcept
354 {
355 IndexType index = m_MinIndex;
356 index.back() = m_MaxIndex.back() + 1;
357 return iterator(index, m_MinIndex, m_MaxIndex, size());
358 }
359
362 [[nodiscard]] constexpr const_iterator
363 cbegin() const noexcept
364 {
365 return this->begin();
366 }
367
369 [[nodiscard]] constexpr const_iterator
370 cend() const noexcept
371 {
372 return this->end();
373 }
374
376 [[nodiscard]] reverse_iterator
377 rbegin() const noexcept
378 {
379 return reverse_iterator(this->end());
380 }
381
383 [[nodiscard]] reverse_iterator
384 rend() const noexcept
385 {
386 return reverse_iterator(this->begin());
387 }
388
390 [[nodiscard]] const_reverse_iterator
391 crbegin() const noexcept
392 {
393 return this->rbegin();
394 }
395
397 [[nodiscard]] const_reverse_iterator
398 crend() const noexcept
399 {
400 return this->rend();
401 }
402
403
405 [[nodiscard]] constexpr size_t
406 size() const noexcept
407 {
408 size_t result = 1;
409
410 for (unsigned int i = 0; i < VDimension; ++i)
411 {
412 result *= ((m_MaxIndex[i] + 1) - m_MinIndex[i]);
413 }
414 return result;
415 }
416
417
419 [[nodiscard]] constexpr bool
420 empty() const noexcept
421 {
422 // When an IndexRange is empty, each index value of m_MaxIndex is less than the corresponding
423 // index value of m_MinIndex. And vice versa: when an IndexRange is non-empty, each index value
424 // of m_MaxIndex is greater than or equal to the corresponding index value of m_MinIndex.
425 // Note that the range contains one element when m_MaxIndex == m_MinIndex.
426 return m_MaxIndex[0] < m_MinIndex[0];
427 }
428
429
430private:
432
433 static constexpr IndexType
434 CalculateMaxIndex(const MinIndexType & minIndex, const SizeType & size)
435 {
436 const bool sizeHasZeroValue = [&size] {
437 for (const auto sizeValue : size)
438 {
439 if (sizeValue == 0)
440 {
441 return true;
442 }
443 }
444 return false;
445 }();
446
447 // Treat any size that has a zero value equally.
448 const SizeType normalizedSize = sizeHasZeroValue ? SizeType{ { 0 } } : size;
449
450 // The `index` is initialized (`{}`), just to support C++17 constexpr.
451 IndexType index{};
452
453 for (unsigned int i = 0; i < VDimension; ++i)
454 {
455 index[i] = minIndex[i] + static_cast<IndexValueType>(normalizedSize[i]) - 1;
456 }
457
458 return index;
459 }
460
461 // IndexRange data members:
462
463 // Minimum (N-dimensional) index.
465
466 // Maximum (N-dimensional) index.
468};
469
470template <unsigned int VDimension>
472
473template <unsigned int VDimension>
475
476/* Creates a range of indices for the specified grid size. */
477template <unsigned int VDimension>
478[[nodiscard]] constexpr auto
480{
481 return ZeroBasedIndexRange<VDimension>(gridSize);
482}
483
484/* Creates a range of indices for the specified image region. */
485template <unsigned int VDimension>
486[[nodiscard]] auto
488{
489 return ImageRegionIndexRange<VDimension>(imageRegion);
490}
491
492/* Creates a range of indices for the image region specified by its index and size. */
493template <unsigned int VDimension>
494[[nodiscard]] auto
495MakeIndexRange(const Index<VDimension> & imageRegionIndex, const Size<VDimension> & imageRegionSize)
496{
497 return ImageRegionIndexRange<VDimension>(ImageRegion<VDimension>{ imageRegionIndex, imageRegionSize });
498}
499
500} // namespace itk
501
502#endif
An image region represents a structured region of data.
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
friend constexpr bool operator<(const const_iterator &lhs, const const_iterator &rhs) noexcept
constexpr const_iterator(const IndexType &index, const MinIndexType &minIndex, const IndexType &maxIndex, const vcl_size_t position) noexcept
constexpr reference operator*() const noexcept
constexpr pointer operator->() const 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
std::reverse_iterator< const_iterator > const_reverse_iterator
constexpr bool empty() const noexcept
typename iterator::MinIndexType MinIndexType
Size< VDimension > SizeType
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
const_iterator iterator
reverse_iterator rbegin() const noexcept
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....
IndexRange< VDimension, true > ZeroBasedIndexRange
IndexRange< VDimension, false > ImageRegionIndexRange
constexpr auto MakeIndexRange(const Size< VDimension > &gridSize)
long IndexValueType
Definition itkIntTypes.h:93
constexpr IndexValueType operator[](unsigned int) const
Represent a n-dimensional index in a n-dimensional image.
Definition itkIndex.h:69
static constexpr Self Filled(const IndexValueType value)
Definition itkIndex.h:496
constexpr reference back()
Definition itkIndex.h:469
Represent a n-dimensional size (bounds) of a n-dimensional image.
Definition itkSize.h:70