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
229 operator*() const noexcept
230 {
231 return *m_BufferIterator;
232 }
233
236 operator++() noexcept
237 {
238 this->Increment<0>();
239 return *this;
240 }
247 operator++(int) noexcept
248 {
249 auto result = *this;
250 ++(*this);
251 return result;
252 }
258 operator--() noexcept
259 {
260 this->Decrement<0>();
261 return *this;
262 }
269 operator--(int) noexcept
270 {
271 auto result = *this;
272 --(*this);
273 return result;
274 }
281 friend bool
282 operator==(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
283 {
284 return lhs.m_BufferIterator == rhs.m_BufferIterator;
285 }
286
287
289 friend bool
290 operator!=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
291 {
292 // Implemented just like the corresponding std::rel_ops operator.
293 return !(lhs == rhs);
294 }
295 };
298 // Inspired by, and originally copied from ImageBase::FastComputeOffset(ind)).
299 static OffsetValueType
300 ComputeOffset(const OffsetTableType & offsetTable, const IndexType & bufferedRegionIndex, const IndexType & index)
301 {
302 OffsetValueType offsetValue = 0;
304 bufferedRegionIndex, index, offsetTable.data(), offsetValue);
305 return offsetValue;
306 }
307
308 // ImageRegionRange data members (strictly private):
309
311
313
315
317
318 // A copy of the offset table of the image.
320
321public:
324 using reverse_iterator = std::reverse_iterator<iterator>;
325 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
326
327
330 ImageRegionRange() noexcept = default;
331
332
337 explicit ImageRegionRange(TImage & image, const RegionType & iterationRegion)
338 : m_BufferBegin{ std::begin(ImageBufferRange{ image }) }
339 ,
340 // Note: Use parentheses instead of curly braces to initialize data members,
341 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
342 m_BufferedRegionIndex(image.TImage::GetBufferedRegion().GetIndex())
343 , m_IterationRegionIndex(iterationRegion.GetIndex())
344 , m_IterationRegionSize(iterationRegion.GetSize())
345 {
346 const OffsetValueType * const offsetTable = image.GetOffsetTable();
347 assert(offsetTable != nullptr);
350 if (iterationRegion.GetNumberOfPixels() > 0) // If region is non-empty
351 {
352 // Check if the iteration region is within the buffered region, similar
353 // to checks in ImageConstIteratorWithIndex(const TImage*, const RegionType&)
354 // and ImageConstIterator::SetRegion(const RegionType&).
355
356 const auto & bufferedRegion = image.GetBufferedRegion();
357
358 itkAssertOrThrowMacro((bufferedRegion.IsInside(iterationRegion)),
359 "Iteration region " << iterationRegion << " is outside of buffered region "
360 << bufferedRegion);
361 }
362
363 std::copy_n(offsetTable, ImageDimension + 1, m_OffsetTable.data());
364 }
365
366
370 explicit ImageRegionRange(TImage & image)
371 : ImageRegionRange(image, image.GetRequestedRegion())
372 {}
373
374
377 begin() const noexcept
378 {
381 OffsetType(),
383 }
388 end() const noexcept
389 {
390 auto endRegionIndex = m_IterationRegionIndex;
391 endRegionIndex.back() += m_IterationRegionSize.back();
394 OffsetType iterationOffset{ {} }; // Initialize offsets to 0, by aggregate initializer
395 *(iterationOffset.rbegin()) = m_IterationRegionSize.back();
396
399 iterationOffset,
401 }
402
406 cbegin() const noexcept
407 {
408 return this->begin();
409 }
410
413 cend() const noexcept
414 {
415 return this->end();
416 }
417
420 rbegin() const noexcept
421 {
422 return reverse_iterator{ this->end() };
423 }
428 rend() const noexcept
429 {
430 return reverse_iterator{ this->begin() };
431 }
436 crbegin() const noexcept
437 {
438 return this->rbegin();
439 }
440
443 crend() const noexcept
444 {
445 return this->rend();
446 }
447
448
450 size_t
451 size() const noexcept
452 {
453 return std::accumulate(
454 m_IterationRegionSize.begin(), m_IterationRegionSize.end(), size_t{ 1 }, std::multiplies<size_t>{});
455 }
460 bool
461 empty() const noexcept
462 {
463 return std::any_of(m_IterationRegionSize.begin(), m_IterationRegionSize.end(), [](const SizeValueType sizeValue) {
464 return sizeValue == 0;
465 });
466 }
471 ~ImageRegionRange() = default;
472};
473
474
475// Deduction guide to avoid compiler warnings (-wctad-maybe-unsupported) when using class template argument deduction.
476template <typename TImage>
478
479} // namespace itk
480
481#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:438