ITK  6.0.0
Insight Toolkit
itkImageRegionRange.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 itkImageRegionRange_h
20#define itkImageRegionRange_h
21
22#include <algorithm> // For any_of and copy_n.
23#include <cassert>
24#include <cstddef> // For ptrdiff_t.
25#include <iterator> // For bidirectional_iterator_tag.
26#include <functional> // For multiplies.
27#include <numeric> // For accumulate.
28#include <type_traits> // For conditional, enable_if, and is_const.
29
30#include "itkImageHelper.h"
31#include "itkImageRegion.h"
32#include "itkImageBufferRange.h"
33
34namespace itk
35{
36
71template <typename TImage>
73{
74private:
76 using ImageDimensionType = typename TImage::ImageDimensionType;
77 using PixelType = typename TImage::PixelType;
78
79 static constexpr bool IsImageTypeConst = std::is_const_v<TImage>;
80 static constexpr ImageDimensionType ImageDimension = TImage::ImageDimension;
81
84 using SizeType = typename TImage::SizeType;
85 using OffsetType = typename TImage::OffsetType;
88
89
102 template <bool VIsConst>
104 {
105 private:
106 // Const and non-const iterators are friends, in order to implement the
107 // constructor that allow conversion from non-const to const iterator.
108 friend class QualifiedIterator<!VIsConst>;
109
110 // ImageRegionRange is a friend, as it should be the only one that can
111 // directly use the private constructor of the iterator.
112 friend class ImageRegionRange;
113
114 // Use either a const or a non-const qualified image buffer iterator.
115 using QualifiedBufferIteratorType = std::conditional_t<VIsConst,
118
119 // QualifiedIterator data members (strictly private):
120
121 // Iterator to the current pixel.
123
124 // A copy of the offset table of the image.
126
127 // N-Dimensional offset relative to the index of the iteration region.
129
130 // Size of the iteration region.
132
133 // Private constructor, used to create the begin and the end iterator of a range.
134 // Only used by its friend class ImageRegionRange.
136 const OffsetTableType & offsetTable,
137 const OffsetType & iterationOffset,
138 const SizeType & regionSize) noexcept
139 : m_BufferIterator(bufferIterator)
140 ,
141 // Note: Use parentheses instead of curly braces to initialize data members,
142 // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
143 m_OffsetTable(offsetTable)
144 , m_IterationOffset(iterationOffset)
145 , m_IterationRegionSize(regionSize)
146 {}
147
148 template <size_t VIndex>
149 void
150 Increment() noexcept
151 {
153
154 if constexpr (VIndex < (ImageDimension - 1))
155 {
156 if (static_cast<SizeValueType>(++m_IterationOffset[VIndex]) >= m_IterationRegionSize[VIndex])
157 {
158 m_IterationOffset[VIndex] = 0;
160 this->Increment<VIndex + 1>();
161 }
162 }
163 else
164 {
165 static_assert(VIndex == (ImageDimension - 1));
166
167 ++m_IterationOffset[VIndex];
168 }
169 }
170
171
172 template <size_t VIndex>
173 void
174 Decrement() noexcept
175 {
177
178 if constexpr (VIndex < (ImageDimension - 1))
179 {
180 if (--m_IterationOffset[VIndex] < 0)
181 {
182 m_IterationOffset[VIndex] = m_IterationRegionSize[VIndex] - 1;
184 this->Decrement<VIndex + 1>();
185 }
186 }
187 else
188 {
189 static_assert(VIndex == (ImageDimension - 1));
190
191 --m_IterationOffset[VIndex];
192 }
193 }
194
195
196 public:
197 // Types conforming the iterator requirements of the C++ standard library:
198 using difference_type = ptrdiff_t;
199 using value_type = typename std::iterator_traits<QualifiedBufferIteratorType>::value_type;
200 using reference = typename std::iterator_traits<QualifiedBufferIteratorType>::reference;
201 using pointer = typename std::iterator_traits<QualifiedBufferIteratorType>::pointer;
202 using iterator_category = std::bidirectional_iterator_tag;
203
212 QualifiedIterator() = default;
213
215 template <bool VIsArgumentConst, typename = std::enable_if_t<VIsConst && !VIsArgumentConst>>
217 : m_BufferIterator(arg.m_BufferIterator)
218 ,
219 // Note: Use parentheses instead of curly braces to initialize data members,
220 // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
221 m_OffsetTable(arg.m_OffsetTable)
222 , m_IterationOffset(arg.m_IterationOffset)
223 , m_IterationRegionSize(arg.m_IterationRegionSize)
224 {}
225
226
228 reference operator*() const noexcept { return *m_BufferIterator; }
229
232 operator++() noexcept
233 {
234 this->Increment<0>();
235 return *this;
236 }
243 operator++(int) noexcept
244 {
245 auto result = *this;
246 ++(*this);
247 return result;
248 }
254 operator--() noexcept
255 {
256 this->Decrement<0>();
257 return *this;
258 }
265 operator--(int) noexcept
266 {
267 auto result = *this;
268 --(*this);
269 return result;
270 }
277 friend bool
278 operator==(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
279 {
280 return lhs.m_BufferIterator == rhs.m_BufferIterator;
281 }
282
283
285 friend bool
286 operator!=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
287 {
288 // Implemented just like the corresponding std::rel_ops operator.
289 return !(lhs == rhs);
290 }
291 };
294 // Inspired by, and originally copied from ImageBase::FastComputeOffset(ind)).
295 static OffsetValueType
296 ComputeOffset(const OffsetTableType & offsetTable, const IndexType & bufferedRegionIndex, const IndexType & index)
297 {
298 OffsetValueType offsetValue = 0;
300 bufferedRegionIndex, index, offsetTable.data(), offsetValue);
301 return offsetValue;
302 }
303
304 // ImageRegionRange data members (strictly private):
305
307
309
311
313
314 // A copy of the offset table of the image.
316
317public:
320 using reverse_iterator = std::reverse_iterator<iterator>;
321 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
322
323
326 ImageRegionRange() noexcept = default;
327
328
333 explicit ImageRegionRange(TImage & image, const RegionType & iterationRegion)
334 : m_BufferBegin{ std::begin(ImageBufferRange{ image }) }
335 ,
336 // Note: Use parentheses instead of curly braces to initialize data members,
337 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
338 m_BufferedRegionIndex(image.TImage::GetBufferedRegion().GetIndex())
339 , m_IterationRegionIndex(iterationRegion.GetIndex())
340 , m_IterationRegionSize(iterationRegion.GetSize())
341 {
342 const OffsetValueType * const offsetTable = image.GetOffsetTable();
343 assert(offsetTable != nullptr);
346 if (iterationRegion.GetNumberOfPixels() > 0) // If region is non-empty
347 {
348 // Check if the iteration region is within the buffered region, similar
349 // to checks in ImageConstIteratorWithIndex(const TImage*, const RegionType&)
350 // and ImageConstIterator::SetRegion(const RegionType&).
351
352 const auto & bufferedRegion = image.GetBufferedRegion();
353
354 itkAssertOrThrowMacro((bufferedRegion.IsInside(iterationRegion)),
355 "Iteration region " << iterationRegion << " is outside of buffered region "
356 << bufferedRegion);
357 }
358
359 std::copy_n(offsetTable, ImageDimension + 1, m_OffsetTable.data());
360 }
361
362
366 explicit ImageRegionRange(TImage & image)
367 : ImageRegionRange(image, image.GetRequestedRegion())
368 {}
369
370
373 begin() const noexcept
374 {
377 OffsetType(),
379 }
384 end() const noexcept
385 {
386 auto endRegionIndex = m_IterationRegionIndex;
387 endRegionIndex.back() += m_IterationRegionSize.back();
390 OffsetType iterationOffset{ {} }; // Initialize offsets to 0, by aggregate initializer
391 *(iterationOffset.rbegin()) = m_IterationRegionSize.back();
392
395 iterationOffset,
397 }
398
402 cbegin() const noexcept
403 {
404 return this->begin();
405 }
406
409 cend() const noexcept
410 {
411 return this->end();
412 }
413
416 rbegin() const noexcept
417 {
418 return reverse_iterator{ this->end() };
419 }
424 rend() const noexcept
425 {
426 return reverse_iterator{ this->begin() };
427 }
432 crbegin() const noexcept
433 {
434 return this->rbegin();
435 }
436
439 crend() const noexcept
440 {
441 return this->rend();
442 }
443
444
446 size_t
447 size() const noexcept
448 {
449 return std::accumulate(
450 m_IterationRegionSize.begin(), m_IterationRegionSize.end(), size_t{ 1 }, std::multiplies<size_t>{});
451 }
456 bool
457 empty() const noexcept
458 {
459 return std::any_of(m_IterationRegionSize.begin(), m_IterationRegionSize.end(), [](const SizeValueType sizeValue) {
460 return sizeValue == 0;
461 });
462 }
467 ~ImageRegionRange() = default;
468};
469
470
471// Deduction guide to avoid compiler warnings (-wctad-maybe-unsupported) when using class template argument deduction.
472template <typename TImage>
473ImageRegionRange(TImage &)->ImageRegionRange<TImage>;
474
475} // namespace itk
476
477#endif
std::conditional_t< UsingPointerAsIterator, QualifiedInternalPixelType *, QualifiedIterator< IsImageTypeConst > > iterator
std::conditional_t< UsingPointerAsIterator, const InternalPixelType *, QualifiedIterator< true > > const_iterator
static void ComputeOffset(const IndexType &bufferedRegionIndex, const IndexType &index, const OffsetValueType offsetTable[], OffsetValueType &offset)
friend bool operator!=(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
typename std::iterator_traits< QualifiedBufferIteratorType >::reference reference
QualifiedIterator & operator--() noexcept
QualifiedIterator operator--(int) noexcept
QualifiedIterator(const QualifiedIterator< VIsArgumentConst > &arg) noexcept
QualifiedIterator & operator++() noexcept
friend bool operator==(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
typename std::iterator_traits< QualifiedBufferIteratorType >::pointer pointer
typename std::iterator_traits< QualifiedBufferIteratorType >::value_type value_type
std::conditional_t< VIsConst, typename ImageBufferRange< TImage >::const_iterator, typename ImageBufferRange< TImage >::iterator > QualifiedBufferIteratorType
QualifiedIterator operator++(int) noexcept
QualifiedIterator(const QualifiedBufferIteratorType &bufferIterator, const OffsetTableType &offsetTable, const OffsetType &iterationOffset, const SizeType &regionSize) noexcept
std::bidirectional_iterator_tag iterator_category
QualifiedBufferIteratorType m_BufferIterator
typename RegionType::IndexType IndexType
typename TImage::ImageDimensionType ImageDimensionType
iterator begin() const noexcept
QualifiedIterator< true > const_iterator
const_reverse_iterator crbegin() const noexcept
OffsetTableType m_OffsetTable
reverse_iterator rbegin() const noexcept
ImageRegionRange(TImage &image)
typename TImage::RegionType RegionType
reverse_iterator rend() const noexcept
BufferIteratorType m_BufferBegin
const_iterator cend() const noexcept
ImageRegionRange() noexcept=default
iterator end() const noexcept
typename ImageBufferRange< TImage >::iterator BufferIteratorType
const_iterator cbegin() const noexcept
typename TImage::SizeType SizeType
static OffsetValueType ComputeOffset(const OffsetTableType &offsetTable, const IndexType &bufferedRegionIndex, const IndexType &index)
std::reverse_iterator< const_iterator > const_reverse_iterator
vcl_size_t size() const noexcept
std::reverse_iterator< iterator > reverse_iterator
const_reverse_iterator crend() const noexcept
typename TImage::PixelType PixelType
typename TImage::OffsetType OffsetType
~ImageRegionRange()=default
QualifiedIterator< IsImageTypeConst > iterator
static constexpr ImageDimensionType ImageDimension
static constexpr bool IsImageTypeConst
bool empty() const noexcept
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
ImageRegionRange(TImage &) -> ImageRegionRange< TImage >
unsigned long SizeValueType
Definition: itkIntTypes.h:86
long OffsetValueType
Definition: itkIntTypes.h:97
OffsetValueType * data()
Definition: itkOffset.h:430