ITK  6.0.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 {}
322 operator*() const noexcept
323 {
324 assert(m_InternalPixelPointer != nullptr);
325
326 using PixelWrapper = std::conditional_t<SupportsDirectPixelAccess, PixelReferenceWrapper, reference>;
327
328 return PixelWrapper{ *m_InternalPixelPointer, m_OptionalAccessorFunctor };
329 }
330
331
334 operator++() noexcept
335 {
336 assert(m_InternalPixelPointer != nullptr);
338 return *this;
339 }
346 operator++(int) noexcept
347 {
348 auto result = *this;
349 ++(*this);
350 return result;
351 }
357 operator--() noexcept
358 {
359 assert(m_InternalPixelPointer != nullptr);
361 return *this;
362 }
369 operator--(int) noexcept
370 {
371 auto result = *this;
372 --(*this);
373 return result;
374 }
381 friend bool
382 operator==(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
383 {
384 return lhs.m_InternalPixelPointer == rhs.m_InternalPixelPointer;
385 }
386
387
389 friend bool
390 operator!=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
391 {
392 // Implemented just like the corresponding std::rel_ops operator.
393 return !(lhs == rhs);
394 }
395
396
398 friend bool
399 operator<(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
400 {
401 return lhs.m_InternalPixelPointer < rhs.m_InternalPixelPointer;
402 }
403
404
406 friend bool
407 operator>(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
408 {
409 // Implemented just like the corresponding std::rel_ops operator.
410 return rhs < lhs;
411 }
412
413
415 friend bool
416 operator<=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
417 {
418 // Implemented just like the corresponding std::rel_ops operator.
419 return !(rhs < lhs);
420 }
421
422
424 friend bool
425 operator>=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
426 {
427 // Implemented just like the corresponding std::rel_ops operator.
428 return !(lhs < rhs);
429 }
430
431
433 friend QualifiedIterator &
435 {
437 return it;
438 }
442 friend QualifiedIterator &
444 {
445 it += (-n);
446 return it;
447 }
451 friend difference_type
452 operator-(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
453 {
454 return lhs.m_InternalPixelPointer - rhs.m_InternalPixelPointer;
455 }
456
457
459 friend QualifiedIterator
461 {
462 return it += n;
463 }
464
465
467 friend QualifiedIterator
469 {
470 return it += n;
471 }
472
473
475 friend QualifiedIterator
477 {
478 return it += (-n);
479 }
480
481
484 operator[](const difference_type n) const noexcept
485 {
486 return *(*this + n);
487 }
488 };
491 static constexpr bool IsImageTypeConst = std::is_const_v<TImage>;
492
493 using QualifiedInternalPixelType = std::conditional_t<IsImageTypeConst, const InternalPixelType, InternalPixelType>;
494
496 {
497 private:
498 TImage & m_Image;
499
500 public:
501 explicit AccessorFunctorInitializer(TImage & image) noexcept
502 : m_Image(image)
503 {}
504
505 operator EmptyAccessorFunctor() const noexcept { return {}; }
506
507 operator AccessorFunctorType() const noexcept
508 {
509 AccessorFunctorType result = {};
510 result.SetPixelAccessor(m_Image.GetPixelAccessor());
511 result.SetBegin(m_Image.TImage::GetBufferPointer());
512 return result;
513 }
514 };
515
516
517 // Helper class for begin() and end(), to ease proper initialization of an
518 // ImageBufferRange iterator (either a 'QualifiedIterator' or a raw pixel pointer).
520 {
521 private:
524
525 public:
526 explicit IteratorInitializer(OptionalAccessorFunctorType optionalAccessorFunctor,
527 QualifiedInternalPixelType * internalPixelPointer) noexcept
528 : m_OptionalAccessorFunctor(optionalAccessorFunctor)
529 , m_InternalPixelPointer(internalPixelPointer)
530 {}
531
532 // Converts to a 'QualifiedIterator' object.
533 template <bool VIsConst>
534 operator QualifiedIterator<VIsConst>() const noexcept
535 {
537 }
538
539 // Converts to a raw pixel pointer.
540 operator QualifiedInternalPixelType *() const noexcept { return m_InternalPixelPointer; }
541 };
542
543
544 // ImageBufferRange data members (strictly private):
545
546 // The accessor functor of the image.
548
549 // Pointer to the buffer of the image.
551
552 // Image size.
554
555public:
556 using const_iterator = std::conditional_t<UsingPointerAsIterator, const InternalPixelType *, QualifiedIterator<true>>;
557 using iterator =
558 std::conditional_t<UsingPointerAsIterator, QualifiedInternalPixelType *, QualifiedIterator<IsImageTypeConst>>;
559 using reverse_iterator = std::reverse_iterator<iterator>;
560 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
561
562
568 ImageBufferRange() = default;
569
570
574 explicit ImageBufferRange(TImage & image)
575 : // Note: Use parentheses instead of curly braces to initialize data members,
576 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
578 , m_ImageBufferPointer{ image.TImage::GetBufferPointer() }
579 , m_NumberOfPixels{ image.TImage::GetBufferedRegion().GetNumberOfPixels() }
580 {}
586 begin() const noexcept
587 {
589 }
590
593 end() const noexcept
594 {
595 return IteratorInitializer{
598 };
599 }
600
604 cbegin() const noexcept
605 {
606 return this->begin();
607 }
608
611 cend() const noexcept
612 {
613 return this->end();
614 }
615
618 rbegin() const noexcept
619 {
620 return reverse_iterator(this->end());
621 }
622
625 rend() const noexcept
626 {
627 return reverse_iterator(this->begin());
628 }
629
632 crbegin() const noexcept
633 {
634 return this->rbegin();
635 }
636
639 crend() const noexcept
640 {
641 return this->rend();
642 }
643
644
646 size_t
647 size() const noexcept
648 {
649 return m_NumberOfPixels;
650 }
651
652
654 bool
655 empty() const noexcept
656 {
657 return m_NumberOfPixels == 0;
658 }
659
660
666 operator[](const size_t n) const noexcept
667 {
668 assert(n < this->size());
669 assert(n <= static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()));
672 return this->begin()[static_cast<ptrdiff_t>(n)];
673 }
674};
675
676
677// Deduction guide to avoid compiler warnings (-wctad-maybe-unsupported) when using class template argument deduction.
678template <typename TImage>
680
681
686template <typename TImage>
688MakeImageBufferRange(TImage * const image)
689{
690 if (image == nullptr)
691 {
692 return {};
693 }
694 else
695 {
696 return ImageBufferRange<TImage>{ *image };
697 }
698}
702} // namespace itk
703#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) noexcept
Definition: itkArray.h:242
ImageBufferRange< TImage > MakeImageBufferRange(TImage *const image)
unsigned long SizeValueType
Definition: itkIntTypes.h:86
ImageBufferRange(TImage &) -> ImageBufferRange< TImage >