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 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 {}
317
318
321 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 }
339
340
344 operator++(int) noexcept
345 {
346 auto result = *this;
347 ++(*this);
348 return result;
349 }
350
351
354 operator--() noexcept
355 {
356 assert(m_InternalPixelPointer != nullptr);
358 return *this;
359 }
360
361
365 operator--(int) noexcept
366 {
367 auto result = *this;
368 --(*this);
369 return result;
370 }
371
372
376 friend bool
377 operator==(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
378 {
379 return lhs.m_InternalPixelPointer == rhs.m_InternalPixelPointer;
380 }
381
382
384 friend bool
385 operator!=(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
386 {
387 // Implemented just like the corresponding std::rel_ops operator.
388 return !(lhs == rhs);
389 }
390
391
393 friend bool
394 operator<(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
395 {
396 return lhs.m_InternalPixelPointer < rhs.m_InternalPixelPointer;
397 }
398
399
401 friend bool
402 operator>(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
403 {
404 // Implemented just like the corresponding std::rel_ops operator.
405 return rhs < lhs;
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 !(lhs < rhs);
424 }
425
426
428 friend QualifiedIterator &
430 {
431 it.m_InternalPixelPointer += n;
432 return it;
433 }
434
436 friend QualifiedIterator &
438 {
439 it += (-n);
440 return it;
441 }
442
444 friend difference_type
445 operator-(const QualifiedIterator & lhs, const QualifiedIterator & rhs) noexcept
446 {
447 return lhs.m_InternalPixelPointer - rhs.m_InternalPixelPointer;
448 }
449
450
452 friend QualifiedIterator
454 {
455 return it += n;
456 }
457
458
460 friend QualifiedIterator
462 {
463 return it += n;
464 }
465
466
468 friend QualifiedIterator
470 {
471 return it += (-n);
472 }
473
474
477 operator[](const difference_type n) const noexcept
478 {
479 return *(*this + n);
480 }
481 };
482
483 static constexpr bool IsImageTypeConst = std::is_const_v<TImage>;
484
485 using QualifiedInternalPixelType = std::conditional_t<IsImageTypeConst, const InternalPixelType, InternalPixelType>;
486
488 {
489 private:
490 TImage & m_Image;
491
492 public:
493 explicit AccessorFunctorInitializer(TImage & image) noexcept
494 : m_Image(image)
495 {}
496
497 operator EmptyAccessorFunctor() const noexcept { return {}; }
498
499 operator AccessorFunctorType() const noexcept
500 {
501 AccessorFunctorType result = {};
502 result.SetPixelAccessor(m_Image.GetPixelAccessor());
503 result.SetBegin(m_Image.TImage::GetBufferPointer());
504 return result;
505 }
506 };
507
508
509 // Helper class for begin() and end(), to ease proper initialization of an
510 // ImageBufferRange iterator (either a 'QualifiedIterator' or a raw pixel pointer).
512 {
513 private:
516
517 public:
518 explicit IteratorInitializer(OptionalAccessorFunctorType optionalAccessorFunctor,
519 QualifiedInternalPixelType * internalPixelPointer) noexcept
520 : m_OptionalAccessorFunctor(optionalAccessorFunctor)
521 , m_InternalPixelPointer(internalPixelPointer)
522 {}
523
524 // Converts to a 'QualifiedIterator' object.
525 template <bool VIsConst>
530
531 // Converts to a raw pixel pointer.
532 operator QualifiedInternalPixelType *() const noexcept { return m_InternalPixelPointer; }
533 };
534
535
536 // ImageBufferRange data members (strictly private):
537
538 // The accessor functor of the image.
540
541 // Pointer to the buffer of the image.
543
544 // Image size.
546
547public:
548 using const_iterator = std::conditional_t<UsingPointerAsIterator, const InternalPixelType *, QualifiedIterator<true>>;
549 using iterator =
550 std::conditional_t<UsingPointerAsIterator, QualifiedInternalPixelType *, QualifiedIterator<IsImageTypeConst>>;
551 using reverse_iterator = std::reverse_iterator<iterator>;
552 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
553
554
560 ImageBufferRange() = default;
561
562
566 explicit ImageBufferRange(TImage & image)
567 : // Note: Use parentheses instead of curly braces to initialize data members,
568 // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
570 , m_ImageBufferPointer{ image.TImage::GetBufferPointer() }
571 , m_NumberOfPixels{ image.TImage::GetBufferedRegion().GetNumberOfPixels() }
572 {}
573
574
577 begin() const noexcept
578 {
580 }
581
584 end() const noexcept
585 {
586 return IteratorInitializer{
589 };
590 }
591
595 cbegin() const noexcept
596 {
597 return this->begin();
598 }
599
602 cend() const noexcept
603 {
604 return this->end();
605 }
606
609 rbegin() const noexcept
610 {
611 return reverse_iterator(this->end());
612 }
613
616 rend() const noexcept
617 {
618 return reverse_iterator(this->begin());
619 }
620
623 crbegin() const noexcept
624 {
625 return this->rbegin();
626 }
627
630 crend() const noexcept
631 {
632 return this->rend();
633 }
634
635
637 size_t
638 size() const noexcept
639 {
640 return m_NumberOfPixels;
641 }
642
643
645 bool
646 empty() const noexcept
647 {
648 return m_NumberOfPixels == 0;
649 }
650
651
657 operator[](const size_t n) const noexcept
658 {
659 assert(n < this->size());
660 assert(n <= static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()));
661
662 return this->begin()[static_cast<ptrdiff_t>(n)];
663 }
664};
665
666
667// Deduction guide to avoid compiler warnings (-wctad-maybe-unsupported) when using class template argument deduction.
668template <typename TImage>
670
671
676template <typename TImage>
678MakeImageBufferRange(TImage * const image)
679{
680 if (image == nullptr)
681 {
682 return {};
683 }
684
685 return ImageBufferRange<TImage>{ *image };
686}
687
688
689} // namespace itk
690#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 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:247
unsigned long SizeValueType
Definition itkIntTypes.h:86
ImageBufferRange< TImage > MakeImageBufferRange(TImage *const image)
ImageBufferRange(TImage &) -> ImageBufferRange< TImage >