ITK  5.0.0
Insight Segmentation and Registration Toolkit
itkImageBufferRange.h
Go to the documentation of this file.
1 /*=========================================================================
2 *
3 * Copyright Insight Software Consortium
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 * http://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, is_same, and is_const.
27 
28 #include "itkMacro.h" // For itkNotUsed.
33 #include "itkImageRegion.h"
34 
35 namespace itk
36 {
37 namespace Experimental
38 {
39 
74 template<typename TImage>
75 class ImageBufferRange final
76 {
77 private:
78  using ImageType = TImage;
79  using PixelType = typename TImage::PixelType;
80  using InternalPixelType = typename TImage::InternalPixelType;
81  using AccessorFunctorType = typename TImage::AccessorFunctorType;
82 
83  // Tells whether or not this range supports direct pixel access. If it does,
84  // iterator::operator*() returns a reference to the internally stored pixel,
85  // otherwise iterator::operator*() returns a proxy, which internally uses the
86  // AccessorFunctor of the image to access the pixel indirectly.
87  constexpr static bool SupportsDirectPixelAccess =
88  std::is_same<PixelType, InternalPixelType>::value &&
89  std::is_same<typename TImage::AccessorType, DefaultPixelAccessor<PixelType>>::value &&
90  std::is_same<AccessorFunctorType, DefaultPixelAccessorFunctor<typename std::remove_const<TImage>::type>>::value;
91 
92  // Tells whether or not this range is using a pointer as iterator.
94 
96 
97  using OptionalAccessorFunctorType = typename std::conditional<SupportsDirectPixelAccess,
99 
100  // PixelProxy: internal class that aims to act like a reference to a pixel:
101  // It acts either like 'PixelType &' or like 'const PixelType &', depending
102  // on its boolean template argument, VIsConst.
103  // The proxy retrieves the pixel value using the AccessorFunctor from the image.
104  // Note: the extra TDummy argument aims to fix AppleClang 6.0.0.6000056 error
105  // "explicit specialization of 'PixelProxy'"and GCC 5.4.0 error "explicit
106  // specialization in non-namespace scope".
107  template <bool VIsConst, typename TDummy = void> class PixelProxy {};
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& operator=(const PixelProxy&) = delete;
125 
126  // Explicitly-defaulted member functions:
127  PixelProxy(const PixelProxy&) ITK_NOEXCEPT = default;
128  ~PixelProxy() = default;
129 
130  // Constructor, called directly by operator*() of the iterator class.
132  const InternalPixelType& internalPixel,
133  const AccessorFunctorType& accessorFunctor) ITK_NOEXCEPT
134  :
135  m_InternalPixel{ internalPixel },
136  m_AccessorFunctor(accessorFunctor)
137  {
138  }
139 
140  // Allows implicit conversion from non-const to const proxy.
141  PixelProxy(const PixelProxy<false>& pixelProxy) ITK_NOEXCEPT
142  :
143  m_InternalPixel{ pixelProxy.m_InternalPixel },
144  m_AccessorFunctor{ pixelProxy.m_AccessorFunctor }
145  {
146  }
147 
148  // Conversion operator.
149  operator PixelType() const ITK_NOEXCEPT
150  {
151  return m_AccessorFunctor.Get(m_InternalPixel);
152  }
153  };
154 
155 
156  // PixelProxy specialization for non-const pixel types:
157  // acts like 'PixelType &'.
158  template <typename TDummy>
159  class PixelProxy<false, TDummy> final
160  {
161  private:
162  // The const proxy is a friend, to ease implementing conversion from
163  // a non-const proxy to a const proxy.
164  friend class PixelProxy<true>;
165 
166  // Reference to the internal representation of the pixel, located in the image buffer.
168 
169  // The accessor functor of the image.
171 
172  public:
173  // Deleted member functions:
174  PixelProxy() = delete;
175 
176  // Explicitly-defaulted member functions:
177  ~PixelProxy() = default;
178  PixelProxy(const PixelProxy&) ITK_NOEXCEPT = default;
179 
180  // Constructor, called directly by operator*() of the iterator class.
181  explicit PixelProxy(
182  InternalPixelType& internalPixel,
183  const AccessorFunctorType& accessorFunctor) ITK_NOEXCEPT
184  :
185  m_InternalPixel{ internalPixel },
186  m_AccessorFunctor(accessorFunctor)
187  {
188  }
189 
190  // Conversion operator.
191  operator PixelType() const ITK_NOEXCEPT
192  {
193  return m_AccessorFunctor.Get(m_InternalPixel);
194  }
195 
196  // Operator to assign a pixel value to the proxy.
197  PixelProxy& operator=(const PixelType& pixelValue) ITK_NOEXCEPT
198  {
199  m_AccessorFunctor.Set(m_InternalPixel, pixelValue);
200  return *this;
201  }
202 
203  // Copy-assignment operator.
204  PixelProxy& operator=(const PixelProxy& pixelProxy) ITK_NOEXCEPT
205  {
206  // Note that this assignment operator only copies the pixel value.
207  // That is the normal behavior when a reference is assigned to another.
208  const PixelType pixelValue = pixelProxy;
209  *this = pixelValue;
210  return *this;
211  }
212 
213 
214  friend void swap(PixelProxy lhs, PixelProxy rhs) ITK_NOEXCEPT
215  {
216  const auto lhsPixelValue = lhs.m_AccessorFunctor.Get(lhs.m_InternalPixel);
217  const auto rhsPixelValue = rhs.m_AccessorFunctor.Get(rhs.m_InternalPixel);
218 
219  // Swap only the pixel values, not the image buffer pointers!
220  lhs.m_AccessorFunctor.Set(lhs.m_InternalPixel, rhsPixelValue);
221  rhs.m_AccessorFunctor.Set(rhs.m_InternalPixel, lhsPixelValue);
222  }
223  };
224 
225 
238  template <bool VIsConst>
239  class QualifiedIterator final
240  {
241  private:
242  // Const and non-const iterators are friends, in order to implement the
243  // constructor that allow conversion from non-const to const iterator.
244  friend class QualifiedIterator<!VIsConst>;
245 
246  // ImageBufferRange is a friend, as it should be the only one that can
247  // directly use the private constructor of the iterator.
248  friend class ImageBufferRange;
249 
250  // Image type class that is either 'const' or non-const qualified, depending on QualifiedIterator and TImage.
251  using QualifiedImageType = typename std::conditional<VIsConst, const ImageType, ImageType>::type;
252 
253  static constexpr bool IsImageTypeConst = std::is_const<QualifiedImageType>::value;
254 
255  using QualifiedInternalPixelType = typename std::conditional<IsImageTypeConst, const InternalPixelType, InternalPixelType>::type;
256 
257  // Pixel type class that is either 'const' or non-const qualified, depending on QualifiedImageType.
258  using QualifiedPixelType = typename std::conditional<IsImageTypeConst, const PixelType, PixelType>::type;
259 
260 
261  // Wraps a reference to a pixel.
263  {
264  public:
266 
267  // Wraps the pixel reference that is specified by the first argument.
268  // Note: the second parameter is unused, but it is there just to support
269  // the use case of iterator::operator*(), which uses either
270  // PixelReferenceWrapper or PixelProxy, interchangeable, in a generic way.
271  // (PixelProxy has an explicit constructor for which the second parameter
272  // is its essential AccessorFunctor parameter!)
274  QualifiedPixelType& pixel,
275  EmptyAccessorFunctor itkNotUsed(accessorFunctor)) ITK_NOEXCEPT
276  :
277  m_Pixel(pixel)
278  {
279  }
280 
281  // Converts implicitly to a reference to the pixel.
282  operator QualifiedPixelType&() const ITK_NOEXCEPT
283  {
284  return m_Pixel;
285  }
286  };
287 
288 
289  // QualifiedIterator data members (strictly private):
290 
291  // The accessor functor of the image.
293 
294  // Pointer to the current pixel.
296 
297  // Private constructor, used to create the begin and the end iterator of a range.
298  // Only used by its friend class ImageBufferRange.
300  const OptionalAccessorFunctorType& accessorFunctor,
301  QualifiedInternalPixelType* const internalPixelPointer) ITK_NOEXCEPT
302  :
303  // Note: Use parentheses instead of curly braces to initialize data members,
304  // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
305  m_OptionalAccessorFunctor(accessorFunctor),
306  m_InternalPixelPointer{ internalPixelPointer }
307  {
308  }
309 
310  public:
311  // Types conforming the iterator requirements of the C++ standard library:
312  using difference_type = std::ptrdiff_t;
314  using reference = typename std::conditional< SupportsDirectPixelAccess,
317  using iterator_category = std::random_access_iterator_tag;
318 
319 
330  QualifiedIterator() = default;
331 
335  :
336  // Note: Use parentheses instead of curly braces to initialize data members,
337  // to avoid AppleClang 6.0.0.6000056 compilation error, "no viable conversion..."
338  m_OptionalAccessorFunctor(arg.m_OptionalAccessorFunctor),
339  m_InternalPixelPointer{ arg.m_InternalPixelPointer }
340  {
341  }
343 
344 
346  reference operator*() const ITK_NOEXCEPT
347  {
348  assert(m_InternalPixelPointer != nullptr);
349 
350  using PixelWrapper = typename std::conditional<SupportsDirectPixelAccess,
352 
353  return PixelWrapper{ *m_InternalPixelPointer, m_OptionalAccessorFunctor };
354  }
355 
356 
359  {
360  assert(m_InternalPixelPointer != nullptr);
362  return *this;
363  }
365 
366 
369  QualifiedIterator operator++(int) ITK_NOEXCEPT
370  {
371  auto result = *this;
372  ++(*this);
373  return result;
374  }
376 
377 
380  {
381  assert(m_InternalPixelPointer != nullptr);
383  return *this;
384  }
386 
387 
390  QualifiedIterator operator--(int) ITK_NOEXCEPT
391  {
392  auto result = *this;
393  --(*this);
394  return result;
395  }
397 
398 
402  friend bool operator==(const QualifiedIterator& lhs, const QualifiedIterator& rhs) ITK_NOEXCEPT
403  {
404  return lhs.m_InternalPixelPointer == rhs.m_InternalPixelPointer;
405  }
406 
407 
409  friend bool operator!=(const QualifiedIterator& lhs, const QualifiedIterator& rhs) ITK_NOEXCEPT
410  {
411  // Implemented just like the corresponding std::rel_ops operator.
412  return !(lhs == rhs);
413  }
414 
415 
417  friend bool operator<(const QualifiedIterator& lhs, const QualifiedIterator& rhs) ITK_NOEXCEPT
418  {
419  return lhs.m_InternalPixelPointer < rhs.m_InternalPixelPointer;
420  }
421 
422 
424  friend bool operator>(const QualifiedIterator& lhs, const QualifiedIterator& rhs) ITK_NOEXCEPT
425  {
426  // Implemented just like the corresponding std::rel_ops operator.
427  return rhs < lhs;
428  }
429 
430 
432  friend bool operator<=(const QualifiedIterator& lhs, const QualifiedIterator& rhs) ITK_NOEXCEPT
433  {
434  // Implemented just like the corresponding std::rel_ops operator.
435  return !(rhs < lhs);
436  }
437 
438 
440  friend bool operator>=(const QualifiedIterator& lhs, const QualifiedIterator& rhs) ITK_NOEXCEPT
441  {
442  // Implemented just like the corresponding std::rel_ops operator.
443  return !(lhs < rhs);
444  }
445 
446 
449  {
450  it.m_InternalPixelPointer += n;
451  return it;
452  }
454 
457  {
458  it += (-n);
459  return it;
460  }
462 
464  friend difference_type operator-(const QualifiedIterator& lhs, const QualifiedIterator& rhs) ITK_NOEXCEPT
465  {
466  return lhs.m_InternalPixelPointer - rhs.m_InternalPixelPointer;
467  }
468 
469 
472  {
473  return it += n;
474  }
475 
476 
479  {
480  return it += n;
481  }
482 
483 
486  {
487  return it += (-n);
488  }
489 
490 
492  reference operator[](const difference_type n) const ITK_NOEXCEPT
493  {
494  return *(*this + n);
495  }
496 
497 
499  QualifiedIterator& operator=(const QualifiedIterator&) ITK_NOEXCEPT = default;
500  };
501 
502  static constexpr bool IsImageTypeConst = std::is_const<TImage>::value;
503 
504  using QualifiedInternalPixelType = typename std::conditional<IsImageTypeConst, const InternalPixelType, InternalPixelType>::type;
505 
507  {
508  private:
510  public:
511  explicit AccessorFunctorInitializer(ImageType& image) ITK_NOEXCEPT
512  :
513  m_Image(image)
514  {
515  }
516 
517  operator EmptyAccessorFunctor() const ITK_NOEXCEPT
518  {
519  return {};
520  }
521 
522  operator AccessorFunctorType() const ITK_NOEXCEPT
523  {
524  AccessorFunctorType result = {};
525  result.SetPixelAccessor(m_Image.GetPixelAccessor());
526  result.SetBegin(m_Image.ImageType::GetBufferPointer());
527  return result;
528  }
529  };
530 
531 
532  // Helper class for begin() and end(), to ease proper initialization of an
533  // ImageBufferRange iterator (either a 'QualifiedIterator' or a raw pixel pointer).
535  {
536  private:
539  public:
541  OptionalAccessorFunctorType optionalAccessorFunctor,
542  QualifiedInternalPixelType* internalPixelPointer) ITK_NOEXCEPT
543  :
544  m_OptionalAccessorFunctor(optionalAccessorFunctor),
545  m_InternalPixelPointer(internalPixelPointer)
546  {
547  }
548 
549  // Converts to a 'QualifiedIterator' object.
550  template <bool VIsConst>
551  operator QualifiedIterator<VIsConst>() const ITK_NOEXCEPT
552  {
554  }
555 
556  // Converts to a raw pixel pointer.
557  operator QualifiedInternalPixelType*() const ITK_NOEXCEPT
558  {
559  return m_InternalPixelPointer;
560  }
561  };
562 
563 
564  // ImageBufferRange data members (strictly private):
565 
566  // The accessor functor of the image.
568 
569  // Pointer to the buffer of the image.
571 
572  // Image size.
574 
575 public:
576  using const_iterator = typename std::conditional<UsingPointerAsIterator,
578  using iterator = typename std::conditional<UsingPointerAsIterator,
580  using reverse_iterator = std::reverse_iterator<iterator>;
581  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
582 
583 
589  ImageBufferRange() = default;
590 
591 
594  explicit ImageBufferRange(ImageType& image)
595  :
596  // Note: Use parentheses instead of curly braces to initialize data members,
597  // to avoid AppleClang 6.0.0.6000056 compile errors, "no viable conversion..."
599  m_ImageBufferPointer{ image.ImageType::GetBufferPointer() },
600  m_NumberOfPixels{ image.ImageType::GetBufferedRegion().GetNumberOfPixels() }
601  {
602  }
604 
605 
607  iterator begin() const ITK_NOEXCEPT
608  {
610  }
611 
613  iterator end() const ITK_NOEXCEPT
614  {
616  }
617 
620  const_iterator cbegin() const ITK_NOEXCEPT
621  {
622  return this->begin();
623  }
624 
626  const_iterator cend() const ITK_NOEXCEPT
627  {
628  return this->end();
629  }
630 
632  reverse_iterator rbegin() const ITK_NOEXCEPT
633  {
634  return reverse_iterator(this->end());
635  }
636 
638  reverse_iterator rend() const ITK_NOEXCEPT
639  {
640  return reverse_iterator(this->begin());
641  }
642 
644  const_reverse_iterator crbegin() const ITK_NOEXCEPT
645  {
646  return this->rbegin();
647  }
648 
650  const_reverse_iterator crend() const ITK_NOEXCEPT
651  {
652  return this->rend();
653  }
654 
655 
657  std::size_t size() const ITK_NOEXCEPT
658  {
659  return m_NumberOfPixels;
660  }
661 
662 
664  bool empty() const ITK_NOEXCEPT
665  {
666  return m_NumberOfPixels == 0;
667  }
668 
669 
674  typename QualifiedIterator<false>::reference operator[](const std::size_t n) const ITK_NOEXCEPT
675  {
676  assert(n < this->size());
677  assert(n <= static_cast<std::size_t>(std::numeric_limits<std::ptrdiff_t>::max()));
679 
680  return this->begin()[static_cast<std::ptrdiff_t>(n)];
681  }
682 };
683 
688 template<typename TImage>
690 {
691  if (image == nullptr)
692  {
693  return {};
694  }
695  else
696  {
697  return ImageBufferRange<TImage>{*image};
698  }
699 }
701 
702 } // namespace Experimental
703 } // namespace itk
704 
705 #endif
friend bool operator!=(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
friend bool operator==(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
reference operator[](const difference_type n) const noexcept
friend QualifiedIterator & operator-=(QualifiedIterator &it, const difference_type n) noexcept
typename std::conditional< IsImageTypeConst, const PixelType, PixelType >::type QualifiedPixelType
IteratorInitializer(OptionalAccessorFunctorType optionalAccessorFunctor, QualifiedInternalPixelType *internalPixelPointer) noexcept
unsigned long SizeValueType
Definition: itkIntTypes.h:83
typename std::conditional< IsImageTypeConst, const InternalPixelType, InternalPixelType >::type QualifiedInternalPixelType
typename TImage::AccessorFunctorType AccessorFunctorType
QualifiedIterator(const OptionalAccessorFunctorType &accessorFunctor, QualifiedInternalPixelType *const internalPixelPointer) noexcept
friend QualifiedIterator & operator+=(QualifiedIterator &it, const difference_type n) noexcept
QualifiedIterator & operator=(const QualifiedIterator &) noexcept=default
friend bool operator<(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
static constexpr bool UsingPointerAsIterator
reverse_iterator rend() const noexcept
friend QualifiedIterator operator-(QualifiedIterator it, const difference_type n) noexcept
QualifiedInternalPixelType * m_ImageBufferPointer
typename TImage::PixelType PixelType
const_reverse_iterator crend() const noexcept
std::reverse_iterator< iterator > reverse_iterator
QualifiedIterator< false >::reference operator[](const std::vcl_size_t n) const noexcept
std::reverse_iterator< const_iterator > const_reverse_iterator
typename std::conditional< UsingPointerAsIterator, QualifiedInternalPixelType *, QualifiedIterator< IsImageTypeConst >>::type iterator
OptionalAccessorFunctorType m_OptionalAccessorFunctor
PixelReferenceWrapper(QualifiedPixelType &pixel, EmptyAccessorFunctor) noexcept
typename TImage::InternalPixelType InternalPixelType
friend bool operator>(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
const_iterator cbegin() const noexcept
std::vcl_size_t size() const noexcept
friend QualifiedIterator operator+(QualifiedIterator it, const difference_type n) noexcept
PixelProxy & operator=(const PixelType &pixelValue) noexcept
const_reverse_iterator crbegin() const noexcept
typename std::conditional< IsImageTypeConst, const InternalPixelType, InternalPixelType >::type QualifiedInternalPixelType
QualifiedIterator(const QualifiedIterator< false > &arg) noexcept
friend difference_type operator-(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
typename std::conditional< SupportsDirectPixelAccess, QualifiedPixelType &, PixelProxy< IsImageTypeConst >>::type reference
reverse_iterator rbegin() const noexcept
typename std::conditional< VIsConst, const ImageType, ImageType >::type QualifiedImageType
typename std::conditional< UsingPointerAsIterator, const InternalPixelType *, QualifiedIterator< true >>::type const_iterator
const_iterator cend() const noexcept
friend QualifiedIterator operator+(const difference_type n, QualifiedIterator it) noexcept
friend bool operator<=(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
static constexpr bool SupportsDirectPixelAccess
PixelProxy & operator=(const PixelProxy &pixelProxy) noexcept
ImageBufferRange< TImage > MakeImageBufferRange(TImage *const image)
PixelProxy(const PixelProxy< false > &pixelProxy) noexcept
friend bool operator>=(const QualifiedIterator &lhs, const QualifiedIterator &rhs) noexcept
typename std::conditional< SupportsDirectPixelAccess, EmptyAccessorFunctor, AccessorFunctorType >::type OptionalAccessorFunctorType
friend void swap(PixelProxy lhs, PixelProxy rhs) noexcept