ITK 6.0.0
Insight Toolkit
 
Loading...
Searching...
No Matches
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 the specified template argument is a template specialization of itk::DefaultPixelAccessorFunctor.
81 template <typename TAccessorFunctor>
82 struct IsDefaultPixelAccessorFunctor : std::false_type
83 {};
84
85 template <typename TAccessorFunctorImage>
86 struct IsDefaultPixelAccessorFunctor<DefaultPixelAccessorFunctor<TAccessorFunctorImage>> : std::true_type
87 {};
88
89 // Tells whether or not this range supports direct pixel access. If it does,
90 // iterator::operator*() returns a reference to the internally stored pixel,
91 // otherwise iterator::operator*() returns a proxy, which internally uses the
92 // AccessorFunctor of the image to access the pixel indirectly.
93 static constexpr bool SupportsDirectPixelAccess =
94 std::is_same_v<PixelType, InternalPixelType> &&
95 std::is_same_v<typename TImage::AccessorType, DefaultPixelAccessor<PixelType>> &&
97
98 // Tells whether or not this range is using a pointer as iterator.
100
102 {};
103
105 std::conditional_t<SupportsDirectPixelAccess, EmptyAccessorFunctor, AccessorFunctorType>;
106
107 // PixelProxy: internal class that aims to act like a reference to a pixel:
108 // It acts either like 'PixelType &' or like 'const PixelType &', depending
109 // on its boolean template argument, VIsConst.
110 // The proxy retrieves the pixel value using the AccessorFunctor from the image.
111 // Note: the extra TDummy argument aims to fix AppleClang 6.0.0.6000056 error
112 // "explicit specialization of 'PixelProxy'"and GCC 5.4.0 error "explicit
113 // specialization in non-namespace scope".
114 template <bool VIsConst, typename TDummy = void>
116 {};
117
118 // PixelProxy specialization for const pixel types:
119 // acts like 'const PixelType &'
120 template <typename TDummy>
121 class PixelProxy<true, TDummy> final
122 {
123 private:
124 // Reference to the internal representation of the pixel, located in the image buffer.
126
127 // The accessor functor of the image.
129
130 public:
131 // Deleted member functions:
132 PixelProxy() = delete;
133 PixelProxy &
134 operator=(const PixelProxy &) = delete;
135
136 // Explicitly-defaulted member functions:
137 PixelProxy(const PixelProxy &) noexcept = default;
138 ~PixelProxy() = default;
139
140 // Constructor, called directly by operator*() of the iterator class.
141 PixelProxy(const InternalPixelType & internalPixel, const AccessorFunctorType & accessorFunctor) noexcept
142 : m_InternalPixel{ internalPixel }
143 , m_AccessorFunctor(accessorFunctor)
144 {}
145
146 // Allows implicit conversion from non-const to const proxy.
147 PixelProxy(const PixelProxy<false> & pixelProxy) noexcept
148 : m_InternalPixel{ pixelProxy.m_InternalPixel }
149 , m_AccessorFunctor{ pixelProxy.m_AccessorFunctor }
150 {}
151
152 // Conversion operator.
153 operator PixelType() const noexcept { return m_AccessorFunctor.Get(m_InternalPixel); }
154 };
155
156
157 // PixelProxy specialization for non-const pixel types:
158 // acts like 'PixelType &'.
159 template <typename TDummy>
160 class PixelProxy<false, TDummy> final
161 {
162 private:
163 // The const proxy is a friend, to ease implementing conversion from
164 // a non-const proxy to a const proxy.
165 friend class PixelProxy<true>;
166
167 // Reference to the internal representation of the pixel, located in the image buffer.
169
170 // The accessor functor of the image.
172
173 public:
174 // Deleted member functions:
175 PixelProxy() = delete;
176
177 // Explicitly-defaulted member functions:
178 ~PixelProxy() = default;
179 PixelProxy(const PixelProxy &) noexcept = default;
180
181 // Constructor, called directly by operator*() of the iterator class.
182 explicit PixelProxy(InternalPixelType & internalPixel, const AccessorFunctorType & accessorFunctor) noexcept
183 : m_InternalPixel{ internalPixel }
184 , m_AccessorFunctor(accessorFunctor)
185 {}
186
187 // Conversion operator.
188 operator PixelType() const noexcept { return m_AccessorFunctor.Get(m_InternalPixel); }
189
190 // Operator to assign a pixel value to the proxy.
191 PixelProxy &
192 operator=(const PixelType & pixelValue) noexcept
193 {
194 m_AccessorFunctor.Set(m_InternalPixel, pixelValue);
195 return *this;
196 }
197
198 // Copy-assignment operator.
199 PixelProxy &
200 operator=(const PixelProxy & pixelProxy) noexcept
201 {
202 // Note that this assignment operator only copies the pixel value.
203 // That is the normal behavior when a reference is assigned to another.
204 const PixelType pixelValue = pixelProxy;
205 *this = pixelValue;
206 return *this;
207 }
208
209
210 friend void
211 swap(PixelProxy lhs, PixelProxy rhs) noexcept
212 {
213 const auto lhsPixelValue = lhs.m_AccessorFunctor.Get(lhs.m_InternalPixel);
214 const auto rhsPixelValue = rhs.m_AccessorFunctor.Get(rhs.m_InternalPixel);
215
216 // Swap only the pixel values, not the image buffer pointers!
217 lhs.m_AccessorFunctor.Set(lhs.m_InternalPixel, rhsPixelValue);
218 rhs.m_AccessorFunctor.Set(rhs.m_InternalPixel, lhsPixelValue);
219 }
220 };
221
222
235 template <bool VIsConst>
237 {
238 private:
239 // Const and non-const iterators are friends, in order to implement the
240 // constructor that allow conversion from non-const to const iterator.
241 friend class QualifiedIterator<!VIsConst>;
242
243 // ImageBufferRange is a friend, as it should be the only one that can
244 // directly use the private constructor of the iterator.
245 friend class ImageBufferRange;
246
247 // Image type class that is either 'const' or non-const qualified, depending on QualifiedIterator and TImage.
248 using QualifiedImageType = std::conditional_t<VIsConst, const TImage, TImage>;
249
250 static constexpr bool IsImageTypeConst = std::is_const_v<QualifiedImageType>;
251
252 using QualifiedInternalPixelType = std::conditional_t<IsImageTypeConst, const InternalPixelType, InternalPixelType>;
253
254 // Pixel type class that is either 'const' or non-const qualified, depending on QualifiedImageType.
255 using QualifiedPixelType = std::conditional_t<IsImageTypeConst, const PixelType, PixelType>;
256
257
258 // Wraps a reference to a pixel.
260 {
261 public:
262 // Wraps the pixel reference that is specified by the first argument.
263 // Note: the second parameter is unused, but it is there just to support
264 // the use case of iterator::operator*(), which uses either
265 // PixelReferenceWrapper or PixelProxy, interchangeable, in a generic way.
266 // (PixelProxy has an explicit constructor for which the second parameter
267 // is its essential AccessorFunctor parameter!)
269 EmptyAccessorFunctor itkNotUsed(accessorFunctor)) noexcept
270 : m_Pixel(pixel)
271 {}
272
273 // Converts implicitly to a reference to the pixel.
274 operator QualifiedPixelType &() const noexcept { return m_Pixel; }
275
276 private:
278 };
279
280
281 // QualifiedIterator data members (strictly private):
282
283 // The accessor functor of the image.
285
286 // Pointer to the current pixel.
288
289 // Private constructor, used to create the begin and the end iterator of a range.
290 // Only used by its friend class ImageBufferRange.
292 QualifiedInternalPixelType * const internalPixelPointer) noexcept
293 : // Note: Use parentheses instead of curly braces to initialize data members,
294 // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
295 m_OptionalAccessorFunctor(accessorFunctor)
296 , m_InternalPixelPointer{ internalPixelPointer }
297 {}
298
299 public:
300 // Types conforming the iterator requirements of the C++ standard library:
301 using difference_type = ptrdiff_t;
303 using reference = std::conditional_t<SupportsDirectPixelAccess, QualifiedPixelType &, PixelProxy<IsImageTypeConst>>;
305 using iterator_category = std::random_access_iterator_tag;
306
307
316 QualifiedIterator() = default;
317
319 template <bool VIsArgumentConst, typename = std::enable_if_t<VIsConst && !VIsArgumentConst>>
321 : // Note: Use parentheses instead of curly braces to initialize data members,
322 // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
323 m_OptionalAccessorFunctor(arg.m_OptionalAccessorFunctor)
324 , m_InternalPixelPointer{ arg.m_InternalPixelPointer }
325 {}
326
327
330 operator*() const noexcept
331 {
332 assert(m_InternalPixelPointer != nullptr);
333
334 using PixelWrapper = std::conditional_t<SupportsDirectPixelAccess, PixelReferenceWrapper, reference>;
335
336 return PixelWrapper{ *m_InternalPixelPointer, m_OptionalAccessorFunctor };
337 }
338
339
342 operator++() noexcept
343 {
344 assert(m_InternalPixelPointer != nullptr);
346 return *this;
347 }
348
349
353 operator++(int) noexcept
354 {
355 auto result = *this;
356 ++(*this);
357 return result;
358 }
359
360
363 operator--() noexcept
364 {
365 assert(m_InternalPixelPointer != nullptr);
367 return *this;
368 }
369
370
374 operator--(int) noexcept
375 {
376 auto result = *this;
377 --(*this);
378 return result;
379 }
380
381
385 friend bool
386 operator==(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
387 {
388 return lhs.m_InternalPixelPointer == rhs.m_InternalPixelPointer;
389 }
390
391
393 friend bool
394 operator!=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
395 {
396 // Implemented just like the corresponding std::rel_ops operator.
397 return !(lhs == rhs);
398 }
399
400
402 friend bool
403 operator<(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
404 {
405 return lhs.m_InternalPixelPointer < rhs.m_InternalPixelPointer;
406 }
407
408
410 friend bool
411 operator>(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
412 {
413 // Implemented just like the corresponding std::rel_ops operator.
414 return rhs < lhs;
415 }
416
417
419 friend bool
420 operator<=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
421 {
422 // Implemented just like the corresponding std::rel_ops operator.
423 return !(rhs < lhs);
424 }
425
426
428 friend bool
429 operator>=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
430 {
431 // Implemented just like the corresponding std::rel_ops operator.
432 return !(lhs < rhs);
433 }
434
435
437 friend QualifiedIterator &
439 {
440 it.m_InternalPixelPointer += n;
441 return it;
442 }
443
445 friend QualifiedIterator &
447 {
448 it += (-n);
449 return it;
450 }
451
453 friend difference_type
454 operator-(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
455 {
456 return lhs.m_InternalPixelPointer - rhs.m_InternalPixelPointer;
457 }
458
459
461 friend QualifiedIterator
463 {
464 return it += n;
465 }
466
467
469 friend QualifiedIterator
471 {
472 return it += n;
473 }
474
475
477 friend QualifiedIterator
479 {
480 return it += (-n);
481 }
482
483
486 operator[](const difference_type n) const noexcept
487 {
488 return *(*this + n);
489 }
490 };
491
492 static constexpr bool IsImageTypeConst = std::is_const_v<TImage>;
493
494 using QualifiedInternalPixelType = std::conditional_t<IsImageTypeConst, const InternalPixelType, InternalPixelType>;
495
497 {
498 private:
499 TImage & m_Image;
500
501 public:
502 explicit AccessorFunctorInitializer(TImage & image) noexcept
503 : m_Image(image)
504 {}
505
506 operator EmptyAccessorFunctor() const noexcept { return {}; }
507
508 operator AccessorFunctorType() const noexcept
509 {
510 AccessorFunctorType result = {};
511 result.SetPixelAccessor(m_Image.GetPixelAccessor());
512 result.SetBegin(m_Image.TImage::GetBufferPointer());
513 return result;
514 }
515 };
516
517
518 // Helper class for begin() and end(), to ease proper initialization of an
519 // ImageBufferRange iterator (either a 'QualifiedIterator' or a raw pixel pointer).
521 {
522 private:
525
526 public:
527 explicit IteratorInitializer(OptionalAccessorFunctorType optionalAccessorFunctor,
528 QualifiedInternalPixelType * internalPixelPointer) noexcept
529 : m_OptionalAccessorFunctor(optionalAccessorFunctor)
530 , m_InternalPixelPointer(internalPixelPointer)
531 {}
532
533 // Converts to a 'QualifiedIterator' object.
534 template <bool VIsConst>
539
540 // Converts to a raw pixel pointer.
541 operator QualifiedInternalPixelType *() const noexcept { return m_InternalPixelPointer; }
542 };
543
544
545 // ImageBufferRange data members (strictly private):
546
547 // The accessor functor of the image.
549
550 // Pointer to the buffer of the image.
552
553 // Image size.
555
556public:
557 using const_iterator = std::conditional_t<UsingPointerAsIterator, const InternalPixelType *, QualifiedIterator<true>>;
558 using iterator =
559 std::conditional_t<UsingPointerAsIterator, QualifiedInternalPixelType *, QualifiedIterator<IsImageTypeConst>>;
560 using reverse_iterator = std::reverse_iterator<iterator>;
561 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
562
563
569 ImageBufferRange() = default;
570
571
575 explicit ImageBufferRange(TImage & image)
576 : // Note: Use parentheses instead of curly braces to initialize data members,
577 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
579 , m_ImageBufferPointer{ image.TImage::GetBufferPointer() }
580 , m_NumberOfPixels{ image.TImage::GetBufferedRegion().GetNumberOfPixels() }
581 {}
582
583
585 [[nodiscard]] iterator
586 begin() const noexcept
587 {
589 }
590
592 [[nodiscard]] iterator
593 end() const noexcept
594 {
595 return IteratorInitializer{
598 };
599 }
600
603 [[nodiscard]] const_iterator
604 cbegin() const noexcept
605 {
606 return this->begin();
607 }
608
610 [[nodiscard]] const_iterator
611 cend() const noexcept
612 {
613 return this->end();
614 }
615
617 [[nodiscard]] reverse_iterator
618 rbegin() const noexcept
619 {
620 return reverse_iterator(this->end());
621 }
622
624 [[nodiscard]] reverse_iterator
625 rend() const noexcept
626 {
627 return reverse_iterator(this->begin());
628 }
629
631 [[nodiscard]] const_reverse_iterator
632 crbegin() const noexcept
633 {
634 return this->rbegin();
635 }
636
638 [[nodiscard]] const_reverse_iterator
639 crend() const noexcept
640 {
641 return this->rend();
642 }
643
644
646 [[nodiscard]] size_t
647 size() const noexcept
648 {
649 return m_NumberOfPixels;
650 }
651
652
654 [[nodiscard]] 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()));
670
671 return this->begin()[static_cast<ptrdiff_t>(n)];
672 }
673};
674
675
676// Deduction guide to avoid compiler warnings (-wctad-maybe-unsupported) when using class template argument deduction.
677template <typename TImage>
679
680
685template <typename TImage>
687MakeImageBufferRange(TImage * const image)
688{
689 if (image == nullptr)
690 {
691 return {};
692 }
693
694 return ImageBufferRange<TImage>{ *image };
695}
696
697
698} // namespace itk
699#endif
Provides a common API for pixel accessors for Image and VectorImage.
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 accessorFunctor) 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
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
std::conditional_t< SupportsDirectPixelAccess, QualifiedPixelType &, PixelProxy< IsImageTypeConst > > reference
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
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
QualifiedInternalPixelType * m_ImageBufferPointer
static constexpr bool IsImageTypeConst
std::reverse_iterator< iterator > reverse_iterator
iterator begin() const noexcept
const_iterator cbegin() const noexcept
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
std::conditional_t< SupportsDirectPixelAccess, EmptyAccessorFunctor, AccessorFunctorType > OptionalAccessorFunctorType
std::conditional_t< UsingPointerAsIterator, QualifiedInternalPixelType *, QualifiedIterator< IsImageTypeConst > > iterator
ImageBufferRange()=default
reverse_iterator rend() const noexcept
std::conditional_t< UsingPointerAsIterator, const InternalPixelType *, QualifiedIterator< true > > const_iterator
typename TImage::PixelType PixelType
QualifiedIterator< false >::reference operator[](const vcl_size_t n) const noexcept
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
void swap(Array< T > &a, Array< T > &b) noexcept
Definition itkArray.h:244
unsigned long SizeValueType
Definition itkIntTypes.h:82
ImageBufferRange< TImage > MakeImageBufferRange(TImage *const image)
ImageBufferRange(TImage &) -> ImageBufferRange< TImage >