ITK  5.4.0
Insight Toolkit
itkImageBufferRange.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 itkImageBufferRange_h
20#define itkImageBufferRange_h
21
22#include <cassert>
23#include <cstddef> // For ptrdiff_t.
24#include <iterator> // For random_access_iterator_tag.
25#include <limits>
26#include <type_traits> // For conditional, enable_if, is_same, and is_const.
27
28#include "itkMacro.h" // For itkNotUsed.
33#include "itkImageRegion.h"
34
35namespace itk
36{
37
72template <typename TImage>
74{
75private:
76 using PixelType = typename TImage::PixelType;
77 using InternalPixelType = typename TImage::InternalPixelType;
78 using AccessorFunctorType = typename TImage::AccessorFunctorType;
79
80 // Tells whether or not this range supports direct pixel access. If it does,
81 // iterator::operator*() returns a reference to the internally stored pixel,
82 // otherwise iterator::operator*() returns a proxy, which internally uses the
83 // AccessorFunctor of the image to access the pixel indirectly.
84 static constexpr bool SupportsDirectPixelAccess =
85 std::is_same_v<PixelType, InternalPixelType> &&
86 std::is_same_v<typename TImage::AccessorType, DefaultPixelAccessor<PixelType>> &&
87 std::is_same_v<AccessorFunctorType, DefaultPixelAccessorFunctor<std::remove_const_t<TImage>>>;
88
89 // Tells whether or not this range is using a pointer as iterator.
91
93 {};
94
96 std::conditional_t<SupportsDirectPixelAccess, EmptyAccessorFunctor, AccessorFunctorType>;
97
98 // PixelProxy: internal class that aims to act like a reference to a pixel:
99 // It acts either like 'PixelType &' or like 'const PixelType &', depending
100 // on its boolean template argument, VIsConst.
101 // The proxy retrieves the pixel value using the AccessorFunctor from the image.
102 // Note: the extra TDummy argument aims to fix AppleClang 6.0.0.6000056 error
103 // "explicit specialization of 'PixelProxy'"and GCC 5.4.0 error "explicit
104 // specialization in non-namespace scope".
105 template <bool VIsConst, typename TDummy = void>
107 {};
108
109 // PixelProxy specialization for const pixel types:
110 // acts like 'const PixelType &'
111 template <typename TDummy>
112 class PixelProxy<true, TDummy> final
113 {
114 private:
115 // Reference to the internal representation of the pixel, located in the image buffer.
117
118 // The accessor functor of the image.
120
121 public:
122 // Deleted member functions:
123 PixelProxy() = delete;
124 PixelProxy &
125 operator=(const PixelProxy &) = delete;
126
127 // Explicitly-defaulted member functions:
128 PixelProxy(const PixelProxy &) noexcept = default;
129 ~PixelProxy() = default;
130
131 // Constructor, called directly by operator*() of the iterator class.
132 PixelProxy(const InternalPixelType & internalPixel, const AccessorFunctorType & accessorFunctor) noexcept
133 : m_InternalPixel{ internalPixel }
134 , m_AccessorFunctor(accessorFunctor)
135 {}
136
137 // Allows implicit conversion from non-const to const proxy.
138 PixelProxy(const PixelProxy<false> & pixelProxy) noexcept
139 : m_InternalPixel{ pixelProxy.m_InternalPixel }
140 , m_AccessorFunctor{ pixelProxy.m_AccessorFunctor }
141 {}
142
143 // Conversion operator.
144 operator PixelType() const noexcept { return m_AccessorFunctor.Get(m_InternalPixel); }
145 };
146
147
148 // PixelProxy specialization for non-const pixel types:
149 // acts like 'PixelType &'.
150 template <typename TDummy>
151 class PixelProxy<false, TDummy> final
152 {
153 private:
154 // The const proxy is a friend, to ease implementing conversion from
155 // a non-const proxy to a const proxy.
156 friend class PixelProxy<true>;
157
158 // Reference to the internal representation of the pixel, located in the image buffer.
160
161 // The accessor functor of the image.
163
164 public:
165 // Deleted member functions:
166 PixelProxy() = delete;
167
168 // Explicitly-defaulted member functions:
169 ~PixelProxy() = default;
170 PixelProxy(const PixelProxy &) noexcept = default;
171
172 // Constructor, called directly by operator*() of the iterator class.
173 explicit PixelProxy(InternalPixelType & internalPixel, const AccessorFunctorType & accessorFunctor) noexcept
174 : m_InternalPixel{ internalPixel }
175 , m_AccessorFunctor(accessorFunctor)
176 {}
177
178 // Conversion operator.
179 operator PixelType() const noexcept { return m_AccessorFunctor.Get(m_InternalPixel); }
180
181 // Operator to assign a pixel value to the proxy.
182 PixelProxy &
183 operator=(const PixelType & pixelValue) noexcept
184 {
185 m_AccessorFunctor.Set(m_InternalPixel, pixelValue);
186 return *this;
187 }
188
189 // Copy-assignment operator.
190 PixelProxy &
191 operator=(const PixelProxy & pixelProxy) noexcept
192 {
193 // Note that this assignment operator only copies the pixel value.
194 // That is the normal behavior when a reference is assigned to another.
195 const PixelType pixelValue = pixelProxy;
196 *this = pixelValue;
197 return *this;
198 }
199
200
201 friend void
202 swap(PixelProxy lhs, PixelProxy rhs) noexcept
203 {
204 const auto lhsPixelValue = lhs.m_AccessorFunctor.Get(lhs.m_InternalPixel);
205 const auto rhsPixelValue = rhs.m_AccessorFunctor.Get(rhs.m_InternalPixel);
206
207 // Swap only the pixel values, not the image buffer pointers!
208 lhs.m_AccessorFunctor.Set(lhs.m_InternalPixel, rhsPixelValue);
209 rhs.m_AccessorFunctor.Set(rhs.m_InternalPixel, lhsPixelValue);
210 }
211 };
212
213
226 template <bool VIsConst>
228 {
229 private:
230 // Const and non-const iterators are friends, in order to implement the
231 // constructor that allow conversion from non-const to const iterator.
232 friend class QualifiedIterator<!VIsConst>;
233
234 // ImageBufferRange is a friend, as it should be the only one that can
235 // directly use the private constructor of the iterator.
236 friend class ImageBufferRange;
237
238 // Image type class that is either 'const' or non-const qualified, depending on QualifiedIterator and TImage.
239 using QualifiedImageType = std::conditional_t<VIsConst, const TImage, TImage>;
240
241 static constexpr bool IsImageTypeConst = std::is_const_v<QualifiedImageType>;
242
243 using QualifiedInternalPixelType = std::conditional_t<IsImageTypeConst, const InternalPixelType, InternalPixelType>;
244
245 // Pixel type class that is either 'const' or non-const qualified, depending on QualifiedImageType.
246 using QualifiedPixelType = std::conditional_t<IsImageTypeConst, const PixelType, PixelType>;
247
248
249 // Wraps a reference to a pixel.
251 {
252 public:
253 // Wraps the pixel reference that is specified by the first argument.
254 // Note: the second parameter is unused, but it is there just to support
255 // the use case of iterator::operator*(), which uses either
256 // PixelReferenceWrapper or PixelProxy, interchangeable, in a generic way.
257 // (PixelProxy has an explicit constructor for which the second parameter
258 // is its essential AccessorFunctor parameter!)
260 EmptyAccessorFunctor itkNotUsed(accessorFunctor)) noexcept
261 : m_Pixel(pixel)
262 {}
263
264 // Converts implicitly to a reference to the pixel.
265 operator QualifiedPixelType &() const noexcept { return m_Pixel; }
266
267 private:
269 };
270
271
272 // QualifiedIterator data members (strictly private):
273
274 // The accessor functor of the image.
276
277 // Pointer to the current pixel.
279
280 // Private constructor, used to create the begin and the end iterator of a range.
281 // Only used by its friend class ImageBufferRange.
283 QualifiedInternalPixelType * const internalPixelPointer) noexcept
284 : // Note: Use parentheses instead of curly braces to initialize data members,
285 // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
286 m_OptionalAccessorFunctor(accessorFunctor)
287 , m_InternalPixelPointer{ internalPixelPointer }
288 {}
289
290 public:
291 // Types conforming the iterator requirements of the C++ standard library:
292 using difference_type = ptrdiff_t;
294 using reference = std::conditional_t<SupportsDirectPixelAccess, QualifiedPixelType &, PixelProxy<IsImageTypeConst>>;
296 using iterator_category = std::random_access_iterator_tag;
297
298
307 QualifiedIterator() = default;
308
310 template <bool VIsArgumentConst, typename = std::enable_if_t<VIsConst && !VIsArgumentConst>>
312 : // Note: Use parentheses instead of curly braces to initialize data members,
313 // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
314 m_OptionalAccessorFunctor(arg.m_OptionalAccessorFunctor)
315 , m_InternalPixelPointer{ arg.m_InternalPixelPointer }
316 {}
321 reference operator*() const noexcept
322 {
323 assert(m_InternalPixelPointer != nullptr);
324
325 using PixelWrapper = std::conditional_t<SupportsDirectPixelAccess, PixelReferenceWrapper, reference>;
326
327 return PixelWrapper{ *m_InternalPixelPointer, m_OptionalAccessorFunctor };
328 }
329
330
333 operator++() noexcept
334 {
335 assert(m_InternalPixelPointer != nullptr);
337 return *this;
338 }
345 operator++(int) noexcept
346 {
347 auto result = *this;
348 ++(*this);
349 return result;
350 }
356 operator--() noexcept
357 {
358 assert(m_InternalPixelPointer != nullptr);
360 return *this;
361 }
368 operator--(int) noexcept
369 {
370 auto result = *this;
371 --(*this);
372 return result;
373 }
380 friend bool
381 operator==(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
382 {
383 return lhs.m_InternalPixelPointer == rhs.m_InternalPixelPointer;
384 }
385
386
388 friend bool
389 operator!=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
390 {
391 // Implemented just like the corresponding std::rel_ops operator.
392 return !(lhs == rhs);
393 }
394
395
397 friend bool
398 operator<(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
399 {
400 return lhs.m_InternalPixelPointer < rhs.m_InternalPixelPointer;
401 }
402
403
405 friend bool
406 operator>(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
407 {
408 // Implemented just like the corresponding std::rel_ops operator.
409 return rhs < lhs;
410 }
411
412
414 friend bool
415 operator<=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
416 {
417 // Implemented just like the corresponding std::rel_ops operator.
418 return !(rhs < lhs);
419 }
420
421
423 friend bool
424 operator>=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
425 {
426 // Implemented just like the corresponding std::rel_ops operator.
427 return !(lhs < rhs);
428 }
429
430
432 friend QualifiedIterator &
434 {
436 return it;
437 }
441 friend QualifiedIterator &
443 {
444 it += (-n);
445 return it;
446 }
450 friend difference_type
451 operator-(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
452 {
453 return lhs.m_InternalPixelPointer - rhs.m_InternalPixelPointer;
454 }
455
456
458 friend QualifiedIterator
460 {
461 return it += n;
462 }
463
464
466 friend QualifiedIterator
468 {
469 return it += n;
470 }
471
472
474 friend QualifiedIterator
476 {
477 return it += (-n);
478 }
479
480
482 reference operator[](const difference_type n) const noexcept { return *(*this + n); }
483 };
484
485 static constexpr bool IsImageTypeConst = std::is_const_v<TImage>;
486
487 using QualifiedInternalPixelType = std::conditional_t<IsImageTypeConst, const InternalPixelType, InternalPixelType>;
488
490 {
491 private:
492 TImage & m_Image;
493
494 public:
495 explicit AccessorFunctorInitializer(TImage & image) noexcept
496 : m_Image(image)
497 {}
498
499 operator EmptyAccessorFunctor() const noexcept { return {}; }
500
501 operator AccessorFunctorType() const noexcept
502 {
503 AccessorFunctorType result = {};
504 result.SetPixelAccessor(m_Image.GetPixelAccessor());
505 result.SetBegin(m_Image.TImage::GetBufferPointer());
506 return result;
507 }
508 };
509
510
511 // Helper class for begin() and end(), to ease proper initialization of an
512 // ImageBufferRange iterator (either a 'QualifiedIterator' or a raw pixel pointer).
514 {
515 private:
518
519 public:
520 explicit IteratorInitializer(OptionalAccessorFunctorType optionalAccessorFunctor,
521 QualifiedInternalPixelType * internalPixelPointer) noexcept
522 : m_OptionalAccessorFunctor(optionalAccessorFunctor)
523 , m_InternalPixelPointer(internalPixelPointer)
524 {}
525
526 // Converts to a 'QualifiedIterator' object.
527 template <bool VIsConst>
528 operator QualifiedIterator<VIsConst>() const noexcept
529 {
531 }
532
533 // Converts to a raw pixel pointer.
534 operator QualifiedInternalPixelType *() const noexcept { return m_InternalPixelPointer; }
535 };
536
537
538 // ImageBufferRange data members (strictly private):
539
540 // The accessor functor of the image.
542
543 // Pointer to the buffer of the image.
545
546 // Image size.
548
549public:
550 using const_iterator = std::conditional_t<UsingPointerAsIterator, const InternalPixelType *, QualifiedIterator<true>>;
551 using iterator =
552 std::conditional_t<UsingPointerAsIterator, QualifiedInternalPixelType *, QualifiedIterator<IsImageTypeConst>>;
553 using reverse_iterator = std::reverse_iterator<iterator>;
554 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
555
556
562 ImageBufferRange() = default;
563
564
568 explicit ImageBufferRange(TImage & image)
569 : // Note: Use parentheses instead of curly braces to initialize data members,
570 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
572 , m_ImageBufferPointer{ image.TImage::GetBufferPointer() }
573 , m_NumberOfPixels{ image.TImage::GetBufferedRegion().GetNumberOfPixels() }
574 {}
580 begin() const noexcept
581 {
583 }
584
587 end() const noexcept
588 {
589 return IteratorInitializer{
592 };
593 }
594
598 cbegin() const noexcept
599 {
600 return this->begin();
601 }
602
605 cend() const noexcept
606 {
607 return this->end();
608 }
609
612 rbegin() const noexcept
613 {
614 return reverse_iterator(this->end());
615 }
616
619 rend() const noexcept
620 {
621 return reverse_iterator(this->begin());
622 }
623
626 crbegin() const noexcept
627 {
628 return this->rbegin();
629 }
630
633 crend() const noexcept
634 {
635 return this->rend();
636 }
637
638
640 size_t
641 size() const noexcept
642 {
643 return m_NumberOfPixels;
644 }
645
646
648 bool
649 empty() const noexcept
650 {
651 return m_NumberOfPixels == 0;
652 }
653
654
659 typename QualifiedIterator<false>::reference operator[](const size_t n) const noexcept
660 {
661 assert(n < this->size());
662 assert(n <= static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()));
665 return this->begin()[static_cast<ptrdiff_t>(n)];
666 }
667};
668
669
670// Deduction guide to avoid compiler warnings (-wctad-maybe-unsupported) when using class template argument deduction.
671template <typename TImage>
672ImageBufferRange(TImage &)->ImageBufferRange<TImage>;
673
674
679template <typename TImage>
681MakeImageBufferRange(TImage * const image)
682{
683 if (image == nullptr)
684 {
685 return {};
686 }
687 else
688 {
689 return ImageBufferRange<TImage>{ *image };
690 }
691}
695} // namespace itk
696#endif
OptionalAccessorFunctorType m_OptionalAccessorFunctor
IteratorInitializer(OptionalAccessorFunctorType optionalAccessorFunctor, QualifiedInternalPixelType *internalPixelPointer) noexcept
QualifiedInternalPixelType * m_InternalPixelPointer
PixelProxy & operator=(const PixelProxy &pixelProxy) noexcept
PixelProxy(const PixelProxy &) noexcept=default
PixelProxy & operator=(const PixelType &pixelValue) noexcept
PixelProxy(InternalPixelType &internalPixel, const AccessorFunctorType &accessorFunctor) noexcept
PixelProxy(const InternalPixelType &internalPixel, const AccessorFunctorType &accessorFunctor) noexcept
PixelProxy(const PixelProxy &) noexcept=default
PixelProxy(const PixelProxy< false > &pixelProxy) noexcept
PixelProxy & operator=(const PixelProxy &)=delete
PixelReferenceWrapper(QualifiedPixelType &pixel, EmptyAccessorFunctor) noexcept
QualifiedIterator & operator++() noexcept
QualifiedIterator(const QualifiedIterator< VIsArgumentConst > &arg) noexcept
friend difference_type operator-(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
QualifiedIterator & operator--() noexcept
friend QualifiedIterator & operator-=(QualifiedIterator &it, const difference_type n) noexcept
friend bool operator!=(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
std::conditional_t< SupportsDirectPixelAccess, QualifiedPixelType &, PixelProxy< IsImageTypeConst > > reference
friend QualifiedIterator operator+(const difference_type n, QualifiedIterator it) noexcept
friend QualifiedIterator & operator+=(QualifiedIterator &it, const difference_type n) noexcept
std::random_access_iterator_tag iterator_category
std::conditional_t< IsImageTypeConst, const PixelType, PixelType > QualifiedPixelType
friend QualifiedIterator operator-(QualifiedIterator it, const difference_type n) noexcept
std::conditional_t< IsImageTypeConst, const InternalPixelType, InternalPixelType > QualifiedInternalPixelType
QualifiedIterator operator++(int) noexcept
reference operator[](const difference_type n) const noexcept
friend bool operator==(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
QualifiedIterator operator--(int) noexcept
friend bool operator<=(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
QualifiedIterator(const OptionalAccessorFunctorType &accessorFunctor, QualifiedInternalPixelType *const internalPixelPointer) noexcept
friend QualifiedIterator operator+(QualifiedIterator it, const difference_type n) noexcept
friend bool operator<(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
OptionalAccessorFunctorType m_OptionalAccessorFunctor
QualifiedInternalPixelType * m_InternalPixelPointer
std::conditional_t< VIsConst, const TImage, TImage > QualifiedImageType
friend bool operator>=(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
friend bool operator>(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
static constexpr bool UsingPointerAsIterator
const_iterator cend() const noexcept
std::conditional_t< UsingPointerAsIterator, QualifiedInternalPixelType *, QualifiedIterator< IsImageTypeConst > > iterator
bool empty() const noexcept
OptionalAccessorFunctorType m_OptionalAccessorFunctor
typename TImage::InternalPixelType InternalPixelType
const_reverse_iterator crbegin() const noexcept
reverse_iterator rbegin() const noexcept
vcl_size_t size() const noexcept
std::conditional_t< UsingPointerAsIterator, const InternalPixelType *, QualifiedIterator< true > > const_iterator
QualifiedInternalPixelType * m_ImageBufferPointer
static constexpr bool IsImageTypeConst
std::reverse_iterator< iterator > reverse_iterator
iterator begin() const noexcept
const_iterator cbegin() const noexcept
ImageBufferRange(TImage &image)
std::conditional_t< IsImageTypeConst, const InternalPixelType, InternalPixelType > QualifiedInternalPixelType
iterator end() const noexcept
const_reverse_iterator crend() const noexcept
std::reverse_iterator< const_iterator > const_reverse_iterator
static constexpr bool SupportsDirectPixelAccess
typename TImage::AccessorFunctorType AccessorFunctorType
ImageBufferRange()=default
reverse_iterator rend() const noexcept
typename TImage::PixelType PixelType
QualifiedIterator< false >::reference operator[](const vcl_size_t n) const noexcept
std::conditional_t< SupportsDirectPixelAccess, EmptyAccessorFunctor, AccessorFunctorType > OptionalAccessorFunctorType
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
void swap(Array< T > &a, Array< T > &b)
Definition: itkArray.h:242
ImageBufferRange< TImage > MakeImageBufferRange(TImage *const image)
unsigned long SizeValueType
Definition: itkIntTypes.h:83
ImageBufferRange(TImage &) -> ImageBufferRange< TImage >