1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkDataArrayTupleRange_Generic.h
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /**
16  * Generic implementation of value ranges and iterators, suitable for
17  * vtkDataArray and all subclasses.
18  */
19 
20 #ifndef vtkDataArrayTupleRange_Generic_h
21 #define vtkDataArrayTupleRange_Generic_h
22 
23 #include "vtkAssume.h"
24 #include "vtkDataArrayAccessor.h"
25 #include "vtkDataArrayMeta.h"
26 
27 #include <algorithm>
28 #include <cassert>
29 #include <iterator>
30 #include <type_traits>
31 
32 #ifndef __VTK_WRAP__
33 
34 VTK_ITER_OPTIMIZE_START
35 
36 namespace vtk
37 {
38 
39 namespace detail
40 {
41 
42 // Forward decs for friends/args
43 template <typename ArrayType, ComponentIdType>
44 struct ConstComponentReference;
45 template <typename ArrayType, ComponentIdType>
46 struct ComponentReference;
47 template <typename ArrayType, ComponentIdType>
48 struct ConstComponentIterator;
49 template <typename ArrayType, ComponentIdType>
50 struct ComponentIterator;
51 template <typename ArrayType, ComponentIdType>
52 struct ConstTupleReference;
53 template <typename ArrayType, ComponentIdType>
54 struct TupleReference;
55 template <typename ArrayType, ComponentIdType>
56 struct ConstTupleIterator;
57 template <typename ArrayType, ComponentIdType>
58 struct TupleIterator;
59 template <typename ArrayType, ComponentIdType>
60 struct TupleRange;
61 
62 //------------------------------------------------------------------------------
63 // Const component reference
64 template <typename ArrayType, ComponentIdType TupleSize>
65 struct ConstComponentReference
66 {
67 private:
68   static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
69   static_assert(IsVtkDataArray<ArrayType>::value, "Invalid array type.");
70 
71   using NumCompsType = GenericTupleSize<TupleSize>;
72   using APIType = GetAPIType<ArrayType>;
73 
74 public:
75   using value_type = APIType;
76 
77   VTK_ITER_INLINE
ConstComponentReferenceConstComponentReference78   ConstComponentReference() noexcept
79     : Array{ nullptr }
80     , NumComps{}
81     , TupleId{ 0 }
82     , ComponentId{ 0 }
83   {
84   }
85 
86   VTK_ITER_INLINE
ConstComponentReferenceConstComponentReference87   ConstComponentReference(
88     ArrayType* array, NumCompsType numComps, TupleIdType tuple, ComponentIdType comp) noexcept
89     : Array{ array }
90     , NumComps{ numComps }
91     , TupleId{ tuple }
92     , ComponentId{ comp }
93   {
94     VTK_ITER_ASSERT(array != nullptr, "Invalid array.");
95     VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components.");
96     VTK_ITER_ASSERT(
97       tuple >= 0 && tuple <= array->GetNumberOfTuples(), "Invalid tuple accessed by iterator.");
98     VTK_ITER_ASSERT(comp >= 0 && comp <= array->GetNumberOfComponents(),
99       "Invalid component accessed by iterator.");
100   }
101 
102   VTK_ITER_INLINE
ConstComponentReferenceConstComponentReference103   ConstComponentReference(const ComponentReference<ArrayType, TupleSize>& o)
104     : Array{ o.Array }
105     , NumComps{ o.NumComps }
106     , TupleId{ o.TupleId }
107     , ComponentId{ o.ComponentId }
108   {
109   }
110 
111   VTK_ITER_INLINE
112   ConstComponentReference(const ConstComponentReference& o) noexcept = default;
113 
114   VTK_ITER_INLINE
115   ConstComponentReference(ConstComponentReference&& o) noexcept = default;
116 
117   VTK_ITER_INLINE
118   ConstComponentReference& operator=(const ConstComponentReference& o) noexcept
119   {
120     VTK_ITER_ASSERT(!this->Array, "Const reference already initialized.");
121     // Initialize the reference.
122     this->Array = o.Array;
123     this->NumComps = o.NumComps;
124     this->TupleId = o.TupleId;
125     this->ComponentId = o.ComponentId;
126   }
127 
128   VTK_ITER_INLINE
129   ConstComponentReference& operator=(ConstComponentReference&& o) noexcept
130   {
131     VTK_ITER_ASSERT(!this->Array, "Const reference already initialized.");
132     // Initialize the reference.
133     this->Array = std::move(o.Array);
134     this->NumComps = std::move(o.NumComps);
135     this->TupleId = std::move(o.TupleId);
136     this->ComponentId = std::move(o.ComponentId);
137   }
138 
139   VTK_ITER_INLINE
APITypeConstComponentReference140   operator APIType() const noexcept
141   {
142     VTK_ITER_ASSUME(this->NumComps.value > 0);
143     VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->NumComps.value);
144     vtkDataArrayAccessor<ArrayType> acc{ this->Array };
145     return acc.Get(this->TupleId, this->ComponentId);
146   }
147 
148 protected:
149   mutable ArrayType* Array;
150   NumCompsType NumComps;
151   TupleIdType TupleId;
152   ComponentIdType ComponentId;
153 };
154 
155 //------------------------------------------------------------------------------
156 // Component reference
157 template <typename ArrayType, ComponentIdType TupleSize>
158 struct ComponentReference
159 {
160 private:
161   static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
162   static_assert(IsVtkDataArray<ArrayType>::value, "Invalid array type.");
163 
164   using NumCompsType = GenericTupleSize<TupleSize>;
165   using APIType = GetAPIType<ArrayType>;
166 
167 public:
168   using value_type = APIType;
169 
170   VTK_ITER_INLINE
ComponentReferenceComponentReference171   ComponentReference() noexcept
172     : Array{ nullptr }
173     , NumComps{}
174     , TupleId{ 0 }
175     , ComponentId{ 0 }
176   {
177   }
178 
179   VTK_ITER_INLINE
ComponentReferenceComponentReference180   ComponentReference(
181     ArrayType* array, NumCompsType numComps, TupleIdType tuple, ComponentIdType comp) noexcept
182     : Array{ array }
183     , NumComps{ numComps }
184     , TupleId{ tuple }
185     , ComponentId{ comp }
186   {
187     VTK_ITER_ASSERT(array != nullptr, "Invalid array.");
188     VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components.");
189     VTK_ITER_ASSERT(
190       tuple >= 0 && tuple <= array->GetNumberOfTuples(), "Invalid tuple accessed by iterator.");
191     VTK_ITER_ASSERT(comp >= 0 && comp <= array->GetNumberOfComponents(),
192       "Invalid component accessed by iterator.");
193   }
194 
195   VTK_ITER_INLINE
196   ComponentReference(const ComponentReference& o) noexcept = default;
197   VTK_ITER_INLINE
198   ComponentReference(ComponentReference&& o) noexcept = default;
199 
200   VTK_ITER_INLINE
201   ComponentReference operator=(const ComponentReference& o) noexcept
202   {
203     if (this->Array)
204     { // Already initialized. Assign the value, not the reference
205       return *this = static_cast<APIType>(o);
206     }
207     else
208     { // Initialize the reference.
209       this->Array = o.Array;
210       this->NumComps = o.NumComps;
211       this->TupleId = o.TupleId;
212       this->ComponentId = o.ComponentId;
213 
214       return *this;
215     }
216   }
217 
218   VTK_ITER_INLINE
219   ComponentReference operator=(ComponentReference&& o) noexcept
220   {
221     if (this->Array)
222     { // Already initialized. Assign the value, not the reference
223       return *this = std::move(static_cast<APIType>(o));
224     }
225     else
226     { // Initialize the reference.
227       this->Array = std::move(o.Array);
228       this->NumComps = std::move(o.NumComps);
229       this->TupleId = std::move(o.TupleId);
230       this->ComponentId = std::move(o.ComponentId);
231 
232       return *this;
233     }
234   }
235 
236   template <typename OArray, ComponentIdType OSize>
237   VTK_ITER_INLINE ComponentReference operator=(const ComponentReference<OArray, OSize>& o) noexcept
238   { // Always copy the value for different reference types:
239     const APIType tmp = o;
240     return *this = std::move(tmp);
241   }
242 
243   VTK_ITER_INLINE
APITypeComponentReference244   operator APIType() const noexcept
245   {
246     VTK_ITER_ASSUME(this->NumComps.value > 0);
247     VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->NumComps.value);
248     vtkDataArrayAccessor<ArrayType> acc{ this->Array };
249     return acc.Get(this->TupleId, this->ComponentId);
250   }
251 
252   VTK_ITER_INLINE
253   ComponentReference operator=(APIType val) noexcept
254   {
255     VTK_ITER_ASSUME(this->NumComps.value > 0);
256     VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->NumComps.value);
257     vtkDataArrayAccessor<ArrayType> acc{ this->Array };
258     acc.Set(this->TupleId, this->ComponentId, val);
259     return *this;
260   }
261 
swapComponentReference262   friend VTK_ITER_INLINE void swap(ComponentReference lhs, ComponentReference rhs) noexcept
263   { // Swap values, not references:
264     APIType tmp = std::move(static_cast<APIType>(lhs));
265     lhs = std::move(static_cast<APIType>(rhs));
266     rhs = std::move(tmp);
267   }
268 
269   template <typename OArray, ComponentIdType OSize>
swapComponentReference270   friend VTK_ITER_INLINE void swap(
271     ComponentReference lhs, ComponentReference<OArray, OSize> rhs) noexcept
272   { // Swap values, not references:
273     using OAPIType = GetAPIType<OArray>;
274     static_assert(
275       std::is_same<APIType, OAPIType>::value, "Cannot swap components with different types.");
276 
277     APIType tmp = std::move(static_cast<APIType>(lhs));
278     lhs = std::move(static_cast<APIType>(rhs));
279     rhs = std::move(tmp);
280   }
281 
swapComponentReference282   friend VTK_ITER_INLINE void swap(ComponentReference lhs, APIType& rhs) noexcept
283   {
284     APIType tmp = std::move(static_cast<APIType>(lhs));
285     lhs = std::move(rhs);
286     rhs = std::move(tmp);
287   }
288 
swapComponentReference289   friend VTK_ITER_INLINE void swap(APIType& lhs, ComponentReference rhs) noexcept
290   {
291     APIType tmp = std::move(lhs);
292     lhs = std::move(static_cast<APIType>(rhs));
293     rhs = std::move(tmp);
294   }
295 
296   VTK_ITER_INLINE
297   ComponentReference operator++() noexcept // prefix
298   {
299     const APIType newVal = *this + 1;
300     *this = newVal;
301     return *this;
302   }
303 
304   VTK_ITER_INLINE
305   APIType operator++(int) noexcept // postfix
306   {
307     const APIType retVal = *this;
308     *this = *this + 1;
309     return retVal;
310   }
311 
312   VTK_ITER_INLINE
313   ComponentReference operator--() noexcept // prefix
314   {
315     const APIType newVal = *this - 1;
316     *this = newVal;
317     return *this;
318   }
319 
320   VTK_ITER_INLINE
321   APIType operator--(int) noexcept // postfix
322   {
323     const APIType retVal = *this;
324     *this = *this - 1;
325     return retVal;
326   }
327 
328 #define VTK_REF_OP_OVERLOADS(Op, ImplOp)                                                           \
329   friend VTK_ITER_INLINE ComponentReference operator Op(                                           \
330     ComponentReference lhs, APIType val) noexcept                                                  \
331   {                                                                                                \
332     const APIType newVal = lhs ImplOp val;                                                         \
333     lhs = newVal;                                                                                  \
334     return lhs;                                                                                    \
335   }                                                                                                \
336   friend VTK_ITER_INLINE ComponentReference operator Op(                                           \
337     ComponentReference lhs, ComponentReference val) noexcept                                       \
338   {                                                                                                \
339     const APIType newVal = lhs ImplOp val;                                                         \
340     lhs = newVal;                                                                                  \
341     return lhs;                                                                                    \
342   }                                                                                                \
343   friend VTK_ITER_INLINE APIType& operator Op(APIType& lhs, ComponentReference val) noexcept       \
344   {                                                                                                \
345     const APIType newVal = lhs ImplOp val;                                                         \
346     lhs = newVal;                                                                                  \
347     return lhs;                                                                                    \
348   }
349 
350   VTK_REF_OP_OVERLOADS(+=, +)
351   VTK_REF_OP_OVERLOADS(-=, -)
352   VTK_REF_OP_OVERLOADS(*=, *)
353   VTK_REF_OP_OVERLOADS(/=, /)
354 
355 #undef VTK_REF_OP_OVERLOADS
356 
357   friend struct ConstComponentReference<ArrayType, TupleSize>;
358   friend struct ComponentIterator<ArrayType, TupleSize>;
359 
360 protected:
361   VTK_ITER_INLINE
362   void CopyReference(const ComponentReference& o) noexcept
363   {
364     this->Array = o.Array;
365     this->NumComps = o.NumComps;
366     this->TupleId = o.TupleId;
367     this->ComponentId = o.ComponentId;
368   }
369 
370   mutable ArrayType* Array;
371   NumCompsType NumComps;
372   TupleIdType TupleId;
373   ComponentIdType ComponentId;
374 };
375 
376 //------------------------------------------------------------------------------
377 // Const component iterator
378 template <typename ArrayType, ComponentIdType TupleSize>
379 struct ConstComponentIterator
380 {
381 private:
382   static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
383   static_assert(IsVtkDataArray<ArrayType>::value, "Invalid array type.");
384 
385   using NumCompsType = GenericTupleSize<TupleSize>;
386 
387 public:
388   using iterator_category = std::random_access_iterator_tag;
389   using value_type = GetAPIType<ArrayType>;
390   using difference_type = ComponentIdType;
391   using pointer = void;
392   using reference = ConstComponentReference<ArrayType, TupleSize>;
393 
394   VTK_ITER_INLINE
395   ConstComponentIterator() noexcept
396     : Array{ nullptr }
397     , TupleId{ 0 }
398     , ComponentId{ 0 }
399   {
400   }
401 
402   VTK_ITER_INLINE
403   ConstComponentIterator(
404     ArrayType* array, NumCompsType numComps, TupleIdType tupleId, ComponentIdType comp) noexcept
405     : Array(array)
406     , NumComps(numComps)
407     , TupleId(tupleId)
408     , ComponentId(comp)
409   {
410     VTK_ITER_ASSERT(array != nullptr, "Invalid array.");
411     VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components.");
412     VTK_ITER_ASSERT(tupleId >= 0 && tupleId <= array->GetNumberOfTuples(),
413       "Const component iterator at invalid tuple id.");
414     VTK_ITER_ASSERT(comp >= 0 && comp <= this->NumComps.value,
415       "Const component iterator at invalid component id.");
416   }
417 
418   VTK_ITER_INLINE
419   ConstComponentIterator(const ComponentIterator<ArrayType, TupleSize>& o) noexcept
420     : Array{ o.GetArray() }
421     , NumComps{ o.GetNumComps() }
422     , TupleId{ o.GetTupleId() }
423     , ComponentId{ o.GetComponentId() }
424   {
425   }
426 
427   VTK_ITER_INLINE
428   ConstComponentIterator(const ConstComponentIterator& o) noexcept = default;
429   VTK_ITER_INLINE
430   ConstComponentIterator& operator=(const ConstComponentIterator& o) noexcept = default;
431 
432   VTK_ITER_INLINE
433   ConstComponentIterator& operator++() noexcept // prefix
434   {
435     ++this->ComponentId;
436     VTK_ITER_ASSERT(this->ComponentId >= 0 && this->ComponentId <= this->NumComps.value,
437       "Const component iterator at invalid component id.");
438     return *this;
439   }
440 
441   VTK_ITER_INLINE
442   ConstComponentIterator operator++(int) noexcept // postfix
443   {
444     return ConstComponentIterator{ this->Array, this->NumComps, this->TupleId,
445       this->ComponentId++ };
446   }
447 
448   VTK_ITER_INLINE
449   ConstComponentIterator& operator--() noexcept // prefix
450   {
451     --this->ComponentId;
452     VTK_ITER_ASSERT(this->ComponentId >= 0 && this->ComponentId <= this->NumComps.value,
453       "Const component iterator at invalid component id.");
454     return *this;
455   }
456 
457   VTK_ITER_INLINE
458   ConstComponentIterator operator--(int) noexcept // postfix
459   {
460     return ConstComponentIterator{ this->Array, this->NumComps, this->TupleId,
461       this->ComponentId-- };
462   }
463 
464   VTK_ITER_INLINE
465   reference operator[](difference_type i) const noexcept
466   {
467     return reference{ this->Array, this->NumComps, this->TupleId, this->ComponentId + i };
468   }
469 
470   VTK_ITER_INLINE
471   reference operator*() const noexcept
472   {
473     return reference{ this->Array, this->NumComps, this->TupleId, this->ComponentId };
474   }
475 
476 #define VTK_TMP_MAKE_OPERATOR(OP)                                                                  \
477   friend VTK_ITER_INLINE bool operator OP(                                                         \
478     const ConstComponentIterator& lhs, const ConstComponentIterator& rhs) noexcept                 \
479   {                                                                                                \
480     VTK_ITER_ASSERT(lhs.Array == rhs.Array, "Mismatched arrays in iterator comparison.");          \
481     VTK_ITER_ASSERT(lhs.TupleId == rhs.TupleId, "Mismatched tuple ids in iterator comparison.");   \
482     VTK_ITER_ASSUME(lhs.NumComps.value > 0);                                                       \
483     VTK_ITER_ASSUME(lhs.NumComps.value == rhs.NumComps.value);                                     \
484     return lhs.ComponentId OP rhs.ComponentId;                                                     \
485   }
486 
487   VTK_TMP_MAKE_OPERATOR(==)
488   VTK_TMP_MAKE_OPERATOR(!=)
489   VTK_TMP_MAKE_OPERATOR(<)
490   VTK_TMP_MAKE_OPERATOR(>)
491   VTK_TMP_MAKE_OPERATOR(<=)
492   VTK_TMP_MAKE_OPERATOR(>=)
493 
494 #undef VTK_TMP_MAKE_OPERATOR
495 
496   VTK_ITER_INLINE
497   ConstComponentIterator& operator+=(difference_type offset) noexcept
498   {
499     this->ComponentId += offset;
500     VTK_ITER_ASSERT(this->ComponentId >= 0 && this->ComponentId <= this->NumComps.value,
501       "Const component iterator at invalid component id.");
502     return *this;
503   }
504 
505   friend VTK_ITER_INLINE ConstComponentIterator operator+(
506     const ConstComponentIterator& it, difference_type offset) noexcept
507   {
508     return ConstComponentIterator{ it.Array, it.NumComps, it.TupleId, it.ComponentId + offset };
509   }
510 
511   friend VTK_ITER_INLINE ConstComponentIterator operator+(
512     difference_type offset, const ConstComponentIterator& it) noexcept
513   {
514     return ConstComponentIterator{ it.Array, it.NumComps, it.TupleId, it.ComponentId + offset };
515   }
516 
517   VTK_ITER_INLINE
518   ConstComponentIterator& operator-=(difference_type offset) noexcept
519   {
520     this->ComponentId -= offset;
521     VTK_ITER_ASSERT(this->ComponentId >= 0 && this->ComponentId <= this->NumComps.value,
522       "Const component iterator at invalid component id.");
523     return *this;
524   }
525 
526   friend VTK_ITER_INLINE ConstComponentIterator operator-(
527     const ConstComponentIterator& it, difference_type offset) noexcept
528   {
529     return ConstComponentIterator{ it.Array, it.NumComps, it.TupleId, it.ComponentId - offset };
530   }
531 
532   friend VTK_ITER_INLINE difference_type operator-(
533     const ConstComponentIterator& it1, const ConstComponentIterator& it2) noexcept
534   {
535     VTK_ITER_ASSERT(it1.Array == it2.Array, "Cannot do math with iterators from different arrays.");
536     VTK_ITER_ASSERT(it1.TupleId == it2.TupleId,
537       "Cannot do math with component iterators from different "
538       "tuples.");
539     return it1.ComponentId - it2.ComponentId;
540   }
541 
542   friend VTK_ITER_INLINE void swap(
543     ConstComponentIterator& lhs, ConstComponentIterator& rhs) noexcept
544   {
545     // Different arrays may use different iterator implementations.
546     VTK_ITER_ASSERT(lhs.Array == rhs.Array, "Cannot swap iterators from different arrays.");
547 
548     using std::swap;
549     swap(lhs.TupleId, rhs.TupleId);
550     swap(lhs.ComponentId, rhs.ComponentId);
551   }
552 
553 private:
554   mutable ArrayType* Array;
555   NumCompsType NumComps;
556   TupleIdType TupleId;
557   ComponentIdType ComponentId;
558 };
559 
560 //------------------------------------------------------------------------------
561 // Component iterator
562 template <typename ArrayType, ComponentIdType TupleSize>
563 struct ComponentIterator
564 {
565 private:
566   static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
567   static_assert(IsVtkDataArray<ArrayType>::value, "Invalid array type.");
568 
569   using NumCompsType = GenericTupleSize<TupleSize>;
570   using APIType = GetAPIType<ArrayType>;
571 
572 public:
573   using iterator_category = std::random_access_iterator_tag;
574   using value_type = APIType;
575   using difference_type = ComponentIdType;
576   using pointer = ComponentReference<ArrayType, TupleSize>;
577   using reference = ComponentReference<ArrayType, TupleSize>;
578 
579   VTK_ITER_INLINE
580   ComponentIterator() noexcept = default;
581 
582   VTK_ITER_INLINE
583   ComponentIterator(
584     ArrayType* array, NumCompsType numComps, TupleIdType tupleId, ComponentIdType comp) noexcept
585     : Ref(array, numComps, tupleId, comp)
586   {
587     VTK_ITER_ASSERT(array != nullptr, "Invalid array.");
588     VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components.");
589     VTK_ITER_ASSERT(tupleId >= 0 && tupleId <= array->GetNumberOfTuples(),
590       "Component iterator at invalid tuple id.");
591     VTK_ITER_ASSERT(
592       comp >= 0 && comp <= numComps.value, "Component iterator at invalid component id.");
593   }
594 
595   VTK_ITER_INLINE
596   ComponentIterator(const ComponentIterator& o) noexcept = default;
597 
598   VTK_ITER_INLINE
599   ComponentIterator& operator=(const ComponentIterator& o) noexcept
600   {
601     this->Ref.CopyReference(o.Ref);
602     return *this;
603   }
604 
605   VTK_ITER_INLINE
606   ComponentIterator& operator++() noexcept // prefix
607   {
608     ++this->Ref.ComponentId;
609     VTK_ITER_ASSERT(this->Ref.ComponentId >= 0 && this->Ref.ComponentId <= this->Ref.NumComps.value,
610       "Component iterator at invalid component id.");
611     return *this;
612   }
613 
614   VTK_ITER_INLINE
615   ComponentIterator operator++(int) noexcept // postfix
616   {
617     return ComponentIterator{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId,
618       this->Ref.ComponentId++ };
619   }
620 
621   VTK_ITER_INLINE
622   ComponentIterator& operator--() noexcept // prefix
623   {
624     --this->Ref.ComponentId;
625     VTK_ITER_ASSERT(this->Ref.ComponentId >= 0 && this->Ref.ComponentId <= this->Ref.NumComps.value,
626       "Component iterator at invalid component id.");
627     return *this;
628   }
629 
630   VTK_ITER_INLINE
631   ComponentIterator operator--(int) noexcept // postfix
632   {
633     return ComponentIterator{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId,
634       this->Ref.ComponentId-- };
635   }
636 
637   VTK_ITER_INLINE
638   reference operator[](difference_type i) const noexcept
639   {
640     return reference{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId,
641       this->Ref.ComponentId + i };
642   }
643 
644   VTK_ITER_INLINE
645   reference operator*() const noexcept { return this->Ref; }
646 
647   VTK_ITER_INLINE
648   const pointer& operator->() const noexcept { return this->Ref; }
649 
650 #define VTK_TMP_MAKE_OPERATOR(OP)                                                                  \
651   friend VTK_ITER_INLINE bool operator OP(                                                         \
652     const ComponentIterator& lhs, const ComponentIterator& rhs) noexcept                           \
653   {                                                                                                \
654     VTK_ITER_ASSERT(                                                                               \
655       lhs.GetArray() == rhs.GetArray(), "Mismatched arrays in iterator comparison.");              \
656     VTK_ITER_ASSERT(                                                                               \
657       lhs.GetTupleId() == rhs.GetTupleId(), "Mismatched tuple ids in iterator comparison.");       \
658     VTK_ITER_ASSUME(lhs.GetNumComps().value > 0);                                                  \
659     VTK_ITER_ASSUME(lhs.GetNumComps().value == rhs.GetNumComps().value);                           \
660     return lhs.GetComponentId() OP rhs.GetComponentId();                                           \
661   }
662 
663   VTK_TMP_MAKE_OPERATOR(==)
664   VTK_TMP_MAKE_OPERATOR(!=)
665   VTK_TMP_MAKE_OPERATOR(<)
666   VTK_TMP_MAKE_OPERATOR(>)
667   VTK_TMP_MAKE_OPERATOR(<=)
668   VTK_TMP_MAKE_OPERATOR(>=)
669 
670 #undef VTK_TMP_MAKE_OPERATOR
671 
672   VTK_ITER_INLINE
673   ComponentIterator& operator+=(difference_type offset) noexcept
674   {
675     this->Ref.ComponentId += offset;
676     VTK_ITER_ASSERT(this->Ref.ComponentId >= 0 && this->Ref.ComponentId <= this->Ref.NumComps.value,
677       "Component iterator at invalid component id.");
678     return *this;
679   }
680 
681   friend VTK_ITER_INLINE ComponentIterator operator+(
682     const ComponentIterator& it, difference_type offset) noexcept
683   {
684     return ComponentIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId(),
685       it.GetComponentId() + offset };
686   }
687 
688   friend VTK_ITER_INLINE ComponentIterator operator+(
689     difference_type offset, const ComponentIterator& it) noexcept
690   {
691     return ComponentIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId(),
692       it.GetComponentId() + offset };
693   }
694 
695   VTK_ITER_INLINE
696   ComponentIterator& operator-=(difference_type offset) noexcept
697   {
698     this->Ref.ComponentId -= offset;
699     VTK_ITER_ASSERT(this->Ref.ComponentId >= 0 && this->Ref.ComponentId <= this->Ref.NumComps.value,
700       "Component iterator at invalid component id.");
701     return *this;
702   }
703 
704   friend VTK_ITER_INLINE ComponentIterator operator-(
705     const ComponentIterator& it, difference_type offset) noexcept
706   {
707     return ComponentIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId(),
708       it.GetComponentId() - offset };
709   }
710 
711   friend VTK_ITER_INLINE difference_type operator-(
712     const ComponentIterator& it1, const ComponentIterator& it2) noexcept
713   {
714     VTK_ITER_ASSERT(it1.GetArray() == it2.GetArray(),
715       "Cannot do math with component iterators from different "
716       "arrays.");
717     VTK_ITER_ASSERT(it1.GetTupleId() == it2.GetTupleId(),
718       "Cannot do math with component iterators from different "
719       "tuples.");
720     return it1.GetComponentId() - it2.GetComponentId();
721   }
722 
723   friend VTK_ITER_INLINE void swap(ComponentIterator& lhs, ComponentIterator& rhs) noexcept
724   {
725     // Different arrays may use different iterator implementations.
726     VTK_ITER_ASSERT(
727       lhs.GetArray() == rhs.GetArray(), "Cannot swap iterators from different arrays.");
728 
729     using std::swap;
730     swap(lhs.GetTupleId(), rhs.GetTupleId());
731     swap(lhs.GetComponentId(), rhs.GetComponentId());
732   }
733 
734   friend struct ConstComponentIterator<ArrayType, TupleSize>;
735 
736 protected:
737   // Needed for access from friend functions. We could just store the array
738   // and ID here instead of the ref, but meh.
739   ArrayType* GetArray() const noexcept { return this->Ref.Array; }
740   TupleIdType& GetTupleId() noexcept { return this->Ref.TupleId; }
741   const TupleIdType& GetTupleId() const noexcept { return this->Ref.TupleId; }
742   ComponentIdType& GetComponentId() noexcept { return this->Ref.ComponentId; }
743   const ComponentIdType& GetComponentId() const noexcept { return this->Ref.ComponentId; }
744   NumCompsType& GetNumComps() noexcept { return this->Ref.NumComps; }
745   const NumCompsType& GetNumComps() const noexcept { return this->Ref.NumComps; }
746 
747   ComponentReference<ArrayType, TupleSize> Ref;
748 };
749 
750 //------------------------------------------------------------------------------
751 // Const tuple reference
752 template <typename ArrayType, ComponentIdType TupleSize>
753 struct ConstTupleReference
754 {
755 private:
756   static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
757   static_assert(IsVtkDataArray<ArrayType>::value, "Invalid array type.");
758 
759   using NumCompsType = GenericTupleSize<TupleSize>;
760   using APIType = GetAPIType<ArrayType>;
761 
762 public:
763   using size_type = ComponentIdType;
764   using value_type = APIType;
765   using iterator = ConstComponentIterator<ArrayType, TupleSize>;
766   using const_iterator = ConstComponentIterator<ArrayType, TupleSize>;
767   using const_reference = ConstComponentReference<ArrayType, TupleSize>;
768 
769   VTK_ITER_INLINE
770   ConstTupleReference() noexcept
771     : Array(nullptr)
772     , TupleId(0)
773   {
774   }
775 
776   VTK_ITER_INLINE
777   ConstTupleReference(ArrayType* array, NumCompsType numComps, TupleIdType tupleId) noexcept
778     : Array(array)
779     , NumComps(numComps)
780     , TupleId(tupleId)
781   {
782     VTK_ITER_ASSERT(array != nullptr, "Invalid array.");
783     VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components.");
784     VTK_ITER_ASSERT(tupleId >= 0 && tupleId <= array->GetNumberOfTuples(),
785       "Const tuple reference at invalid tuple id.");
786   }
787 
788   VTK_ITER_INLINE
789   ConstTupleReference(const TupleReference<ArrayType, TupleSize>& o) noexcept
790     : Array{ o.Array }
791     , NumComps{ o.NumComps }
792     , TupleId{ o.TupleId }
793   {
794   }
795 
796   VTK_ITER_INLINE
797   ConstTupleReference(const ConstTupleReference&) noexcept = default;
798   VTK_ITER_INLINE
799   ConstTupleReference(ConstTupleReference&&) noexcept = default;
800 
801   // Allow this type to masquerade as a pointer, so that tupleIiter->foo works.
802   VTK_ITER_INLINE
803   ConstTupleReference* operator->() noexcept { return this; }
804   VTK_ITER_INLINE
805   const ConstTupleReference* operator->() const noexcept { return this; }
806 
807   // Caller must ensure that there are size() elements in array.
808   VTK_ITER_INLINE
809   void GetTuple(APIType* tuple) const noexcept
810   {
811     VTK_ITER_ASSUME(this->NumComps.value > 0);
812     VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->NumComps.value);
813     vtkDataArrayAccessor<ArrayType> acc{ this->Array };
814     acc.Get(this->TupleId, tuple);
815   }
816 
817   // skips some runtime checks when both sizes are fixed:
818   template <typename OArrayType, ComponentIdType OSize>
819   VTK_ITER_INLINE EnableIfStaticTupleSizes<TupleSize, OSize, bool> operator==(
820     const TupleReference<OArrayType, OSize>& other) const noexcept
821   {
822     // Check that types are convertible:
823     using OAPIType = GetAPIType<OArrayType>;
824     static_assert(
825       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when comparing tuples.");
826 
827     // SFINAE guarantees that the tuple sizes are not dynamic in this overload:
828     static_assert(TupleSize == OSize, "Cannot compare tuples with different sizes.");
829 
830     return std::equal(this->cbegin(), this->cend(), other.cbegin());
831   }
832 
833   // Needs a runtime check:
834   template <typename OArrayType, ComponentIdType OSize>
835   VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic<TupleSize, OSize, bool> operator==(
836     const TupleReference<OArrayType, OSize>& other) const noexcept
837   {
838     // Check that types are convertible:
839     using OAPIType = GetAPIType<OArrayType>;
840     static_assert(
841       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when comparing tuples.");
842 
843     VTK_ITER_ASSERT(
844       other.size() == this->NumComps.value, "Cannot compare tuples with different sizes.");
845 
846     return std::equal(this->cbegin(), this->cend(), other.cbegin());
847   }
848 
849   // skips some runtime checks when both sizes are fixed:
850   template <typename OArrayType, ComponentIdType OSize>
851   VTK_ITER_INLINE EnableIfStaticTupleSizes<TupleSize, OSize, bool> operator==(
852     const ConstTupleReference<OArrayType, OSize>& other) const noexcept
853   {
854     // Check that types are convertible:
855     using OAPIType = GetAPIType<OArrayType>;
856     static_assert(
857       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when comparing tuples.");
858 
859     // SFINAE guarantees that the tuple sizes are not dynamic in this overload:
860     static_assert(TupleSize == OSize, "Cannot compare tuples with different sizes.");
861 
862     return std::equal(this->cbegin(), this->cend(), other.cbegin());
863   }
864 
865   // Needs a runtime check:
866   template <typename OArrayType, ComponentIdType OSize>
867   VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic<TupleSize, OSize, bool> operator==(
868     const ConstTupleReference<OArrayType, OSize>& other) const noexcept
869   {
870     // Check that types are convertible:
871     using OAPIType = GetAPIType<OArrayType>;
872     static_assert(
873       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when comparing tuples.");
874 
875     VTK_ITER_ASSERT(
876       other.size() == this->NumComps.value, "Cannot compare tuples with different sizes.");
877 
878     return std::equal(this->cbegin(), this->cend(), other.cbegin());
879   }
880 
881   template <typename OArrayType, ComponentIdType OSize>
882   VTK_ITER_INLINE bool operator!=(const TupleReference<OArrayType, OSize>& o) const noexcept
883   {
884     return !(*this == o);
885   }
886 
887   template <typename OArrayT, ComponentIdType OSize>
888   VTK_ITER_INLINE bool operator!=(const ConstTupleReference<OArrayT, OSize>& o) const noexcept
889   {
890     return !(*this == o);
891   }
892 
893   VTK_ITER_INLINE
894   const_reference operator[](size_type i) const noexcept
895   {
896     return const_reference{ this->Array, this->NumComps, this->TupleId, i };
897   }
898 
899   VTK_ITER_INLINE
900   size_type size() const noexcept { return this->NumComps.value; }
901 
902   VTK_ITER_INLINE
903   const_iterator begin() const noexcept { return this->NewConstIterator(0); }
904   VTK_ITER_INLINE
905   const_iterator end() const noexcept { return this->NewConstIterator(this->NumComps.value); }
906 
907   VTK_ITER_INLINE
908   const_iterator cbegin() const noexcept { return this->NewConstIterator(0); }
909   VTK_ITER_INLINE
910   const_iterator cend() const noexcept { return this->NewConstIterator(this->NumComps.value); }
911 
912   friend struct ConstTupleIterator<ArrayType, TupleSize>;
913 
914 protected:
915   // Intentionally hidden:
916   VTK_ITER_INLINE
917   ConstTupleReference& operator=(const ConstTupleReference&) noexcept = default;
918 
919   VTK_ITER_INLINE
920   const_iterator NewConstIterator(ComponentIdType comp) const noexcept
921   {
922     VTK_ITER_ASSUME(this->NumComps.value > 0);
923     return const_iterator{ this->Array, this->NumComps, this->TupleId, comp };
924   }
925 
926   VTK_ITER_INLINE
927   void CopyReference(const ConstTupleReference& o) noexcept
928   {
929     // Must use same array, other array types may use different implementations.
930     VTK_ITER_ASSERT(this->Array == o.Array, "Cannot copy reference objects between arrays.");
931     this->NumComps = o.NumComps;
932     this->TupleId = o.TupleId;
933   }
934 
935   mutable ArrayType* Array;
936   NumCompsType NumComps;
937   TupleIdType TupleId;
938 };
939 
940 //------------------------------------------------------------------------------
941 // Tuple reference
942 template <typename ArrayType, ComponentIdType TupleSize>
943 struct TupleReference
944 {
945 private:
946   static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
947   static_assert(IsVtkDataArray<ArrayType>::value, "Invalid array type.");
948 
949   using NumCompsType = GenericTupleSize<TupleSize>;
950   using APIType = GetAPIType<ArrayType>;
951 
952 public:
953   using size_type = ComponentIdType;
954   using value_type = APIType;
955   using iterator = ComponentIterator<ArrayType, TupleSize>;
956   using const_iterator = ConstComponentIterator<ArrayType, TupleSize>;
957   using reference = ComponentReference<ArrayType, TupleSize>;
958   using const_reference = ConstComponentReference<ArrayType, TupleSize>;
959 
960   VTK_ITER_INLINE
961   TupleReference() noexcept
962     : Array(nullptr)
963     , TupleId(0)
964   {
965   }
966 
967   VTK_ITER_INLINE
968   TupleReference(ArrayType* array, NumCompsType numComps, TupleIdType tupleId) noexcept
969     : Array(array)
970     , NumComps(numComps)
971     , TupleId(tupleId)
972   {
973     VTK_ITER_ASSERT(array != nullptr, "Invalid array.");
974     VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components.");
975     VTK_ITER_ASSERT(tupleId >= 0 && tupleId <= array->GetNumberOfTuples(),
976       "Tuple reference at invalid tuple id.");
977   }
978 
979   VTK_ITER_INLINE
980   TupleReference(const TupleReference&) = default;
981   VTK_ITER_INLINE
982   TupleReference(TupleReference&&) = default;
983 
984   // Allow this type to masquerade as a pointer, so that tupleIiter->foo works.
985   VTK_ITER_INLINE
986   TupleReference* operator->() noexcept { return this; }
987   VTK_ITER_INLINE
988   const TupleReference* operator->() const noexcept { return this; }
989 
990   // Caller must ensure that there are size() elements in array.
991   VTK_ITER_INLINE
992   void GetTuple(APIType* tuple) const noexcept
993   {
994     VTK_ITER_ASSUME(this->NumComps.value > 0);
995     VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->NumComps.value);
996     vtkDataArrayAccessor<ArrayType> acc{ this->Array };
997     acc.Get(this->TupleId, tuple);
998   }
999 
1000   // Caller must ensure that there are size() elements in array.
1001   VTK_ITER_INLINE
1002   void SetTuple(const APIType* tuple) noexcept
1003   {
1004     VTK_ITER_ASSUME(this->NumComps.value > 0);
1005     VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->NumComps.value);
1006     vtkDataArrayAccessor<ArrayType> acc{ this->Array };
1007     acc.Set(this->TupleId, tuple);
1008   }
1009 
1010   VTK_ITER_INLINE
1011   TupleReference& operator=(const TupleReference& other) noexcept
1012   {
1013     std::copy_n(other.cbegin(), this->NumComps.value, this->begin());
1014     return *this;
1015   }
1016 
1017   // skips some runtime checks when both sizes are fixed:
1018   template <typename OArrayType, ComponentIdType OSize>
1019   VTK_ITER_INLINE EnableIfStaticTupleSizes<TupleSize, OSize, TupleReference&> operator=(
1020     const TupleReference<OArrayType, OSize>& other) noexcept
1021   {
1022     // Check that types are convertible:
1023     using OAPIType = GetAPIType<OArrayType>;
1024     static_assert(
1025       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when assigning tuples.");
1026 
1027     // SFINAE guarantees that the tuple sizes are not dynamic in this overload:
1028     static_assert(TupleSize == OSize, "Cannot assign tuples with different sizes.");
1029 
1030     std::copy_n(other.cbegin(), OSize, this->begin());
1031     return *this;
1032   }
1033 
1034   // Needs a runtime check:
1035   template <typename OArrayType, ComponentIdType OSize>
1036   VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic<TupleSize, OSize, TupleReference&> operator=(
1037     const TupleReference<OArrayType, OSize>& other) noexcept
1038   {
1039     // Check that types are convertible:
1040     using OAPIType = GetAPIType<OArrayType>;
1041     static_assert(
1042       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when assigning tuples.");
1043 
1044     VTK_ITER_ASSERT(
1045       other.size() == this->NumComps.value, "Cannot assign tuples with different sizes.");
1046 
1047     std::copy_n(other.cbegin(), this->NumComps.value, this->begin());
1048     return *this;
1049   }
1050 
1051   // skips some runtime checks when both sizes are fixed:
1052   template <typename OArrayType, ComponentIdType OSize>
1053   VTK_ITER_INLINE EnableIfStaticTupleSizes<TupleSize, OSize, TupleReference&> operator=(
1054     const ConstTupleReference<OArrayType, OSize>& other) noexcept
1055   {
1056     // Check that types are convertible:
1057     using OAPIType = GetAPIType<OArrayType>;
1058     static_assert(
1059       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when assigning tuples.");
1060 
1061     // SFINAE guarantees that the tuple sizes are not dynamic in this overload:
1062     static_assert(TupleSize == OSize, "Cannot assign tuples with different sizes.");
1063 
1064     std::copy_n(other.cbegin(), OSize, this->begin());
1065     return *this;
1066   }
1067 
1068   // Needs a runtime check:
1069   template <typename OArrayType, ComponentIdType OSize>
1070   VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic<TupleSize, OSize, TupleReference&> operator=(
1071     const ConstTupleReference<OArrayType, OSize>& other) noexcept
1072   {
1073     // Check that types are convertible:
1074     using OAPIType = GetAPIType<OArrayType>;
1075     static_assert(
1076       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when assigning tuples.");
1077 
1078     VTK_ITER_ASSERT(
1079       other.size() == this->NumComps.value, "Cannot assign tuples with different sizes.");
1080 
1081     std::copy_n(other.cbegin(), this->NumComps.value, this->begin());
1082     return *this;
1083   }
1084 
1085   // skips some runtime checks when both sizes are fixed:
1086   template <typename OArrayType, ComponentIdType OSize>
1087   VTK_ITER_INLINE EnableIfStaticTupleSizes<TupleSize, OSize, bool> operator==(
1088     const TupleReference<OArrayType, OSize>& other) const noexcept
1089   {
1090     // Check that types are convertible:
1091     using OAPIType = GetAPIType<OArrayType>;
1092     static_assert(
1093       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when comparing tuples.");
1094 
1095     // SFINAE guarantees that the tuple sizes are not dynamic in this overload:
1096     static_assert(TupleSize == OSize, "Cannot compare tuples with different sizes.");
1097 
1098     return std::equal(this->cbegin(), this->cend(), other.cbegin());
1099   }
1100 
1101   // Needs a runtime check:
1102   template <typename OArrayType, ComponentIdType OSize>
1103   VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic<TupleSize, OSize, bool> operator==(
1104     const TupleReference<OArrayType, OSize>& other) const noexcept
1105   {
1106     // Check that types are convertible:
1107     using OAPIType = GetAPIType<OArrayType>;
1108     static_assert(
1109       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when comparing tuples.");
1110 
1111     VTK_ITER_ASSERT(
1112       other.size() == this->NumComps.value, "Cannot compare tuples with different sizes.");
1113 
1114     return std::equal(this->cbegin(), this->cend(), other.cbegin());
1115   }
1116 
1117   // skips some runtime checks when both sizes are fixed:
1118   template <typename OArrayType, ComponentIdType OSize>
1119   VTK_ITER_INLINE EnableIfStaticTupleSizes<TupleSize, OSize, bool> operator==(
1120     const ConstTupleReference<OArrayType, OSize>& other) const noexcept
1121   {
1122     // Check that types are convertible:
1123     using OAPIType = GetAPIType<OArrayType>;
1124     static_assert(
1125       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when comparing tuples.");
1126 
1127     // SFINAE guarantees that the tuple sizes are not dynamic in this overload:
1128     static_assert(TupleSize == OSize, "Cannot compare tuples with different sizes.");
1129 
1130     return std::equal(this->cbegin(), this->cend(), other.cbegin());
1131   }
1132 
1133   // Needs a runtime check:
1134   template <typename OArrayType, ComponentIdType OSize>
1135   VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic<TupleSize, OSize, bool> operator==(
1136     const ConstTupleReference<OArrayType, OSize>& other) const noexcept
1137   {
1138     // Check that types are convertible:
1139     using OAPIType = GetAPIType<OArrayType>;
1140     static_assert(
1141       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when comparing tuples.");
1142 
1143     VTK_ITER_ASSERT(
1144       other.size() == this->NumComps.value, "Cannot compare tuples with different sizes.");
1145 
1146     return std::equal(this->cbegin(), this->cend(), other.cbegin());
1147   }
1148 
1149   template <typename OArrayType, ComponentIdType OSize>
1150   VTK_ITER_INLINE bool operator!=(const TupleReference<OArrayType, OSize>& o) const noexcept
1151   {
1152     return !(*this == o);
1153   }
1154 
1155   template <typename OArray, ComponentIdType OSize>
1156   VTK_ITER_INLINE bool operator!=(const ConstTupleReference<OArray, OSize>& o) const noexcept
1157   {
1158     return !(*this == o);
1159   }
1160 
1161   // skips some runtime checks:
1162   template <typename OArrayType, ComponentIdType OSize>
1163   VTK_ITER_INLINE EnableIfStaticTupleSizes<TupleSize, OSize, void> swap(
1164     TupleReference<OArrayType, OSize> other) noexcept
1165   {
1166     // Check that types are convertible:
1167     using OAPIType = GetAPIType<OArrayType>;
1168     static_assert(
1169       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when swapping tuples.");
1170 
1171     // SFINAE guarantees that the tuple sizes are not dynamic in this overload:
1172     static_assert(TupleSize == OSize, "Cannot swap tuples with different sizes.");
1173 
1174     std::swap_ranges(this->begin(), this->end(), other.begin());
1175   }
1176 
1177   // Needs a runtime check:
1178   template <typename OArrayType, ComponentIdType OSize>
1179   VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic<TupleSize, OSize, void> swap(
1180     TupleReference<OArrayType, OSize> other) noexcept
1181   {
1182     // Check that types are convertible:
1183     using OAPIType = GetAPIType<OArrayType>;
1184     static_assert(
1185       (std::is_convertible<OAPIType, APIType>{}), "Incompatible types when swapping tuples.");
1186 
1187     VTK_ITER_ASSERT(
1188       other.size() == this->NumComps.value, "Cannot swap tuples with different sizes.");
1189 
1190     std::swap_ranges(this->begin(), this->end(), other.begin());
1191   }
1192 
1193   friend VTK_ITER_INLINE void swap(TupleReference a, TupleReference b) noexcept { a.swap(b); }
1194 
1195   template <typename OArray, ComponentIdType OSize>
1196   friend VTK_ITER_INLINE void swap(TupleReference a, TupleReference<OArray, OSize> b) noexcept
1197   {
1198     a.swap(b);
1199   }
1200 
1201   VTK_ITER_INLINE
1202   reference operator[](size_type i) noexcept
1203   {
1204     return reference{ this->Array, this->NumComps, this->TupleId, i };
1205   }
1206 
1207   VTK_ITER_INLINE
1208   const_reference operator[](size_type i) const noexcept
1209   {
1210     // Let the reference type do the lookup during implicit conversion.
1211     return const_reference{ this->Array, this->NumComps, this->TupleId, i };
1212   }
1213 
1214   VTK_ITER_INLINE
1215   void fill(const value_type& v) noexcept { std::fill(this->begin(), this->end(), v); }
1216 
1217   VTK_ITER_INLINE
1218   size_type size() const noexcept { return this->NumComps.value; }
1219 
1220   VTK_ITER_INLINE
1221   iterator begin() noexcept { return this->NewIterator(0); }
1222   VTK_ITER_INLINE
1223   iterator end() noexcept { return this->NewIterator(this->NumComps.value); }
1224 
1225   VTK_ITER_INLINE
1226   const_iterator begin() const noexcept { return this->NewConstIterator(0); }
1227   VTK_ITER_INLINE
1228   const_iterator end() const noexcept { return this->NewConstIterator(this->NumComps.value); }
1229 
1230   VTK_ITER_INLINE
1231   const_iterator cbegin() const noexcept { return this->NewConstIterator(0); }
1232   VTK_ITER_INLINE
1233   const_iterator cend() const noexcept { return this->NewConstIterator(this->NumComps.value); }
1234 
1235   friend struct ConstTupleReference<ArrayType, TupleSize>;
1236   friend struct TupleIterator<ArrayType, TupleSize>;
1237 
1238 protected:
1239   VTK_ITER_INLINE
1240   iterator NewIterator(ComponentIdType comp) const noexcept
1241   {
1242     VTK_ITER_ASSUME(this->NumComps.value > 0);
1243     return iterator{ this->Array, this->NumComps, this->TupleId, comp };
1244   }
1245 
1246   VTK_ITER_INLINE
1247   const_iterator NewConstIterator(ComponentIdType comp) const noexcept
1248   {
1249     VTK_ITER_ASSUME(this->NumComps.value > 0);
1250     return const_iterator{ this->Array, this->NumComps, this->TupleId, comp };
1251   }
1252 
1253   VTK_ITER_INLINE
1254   void CopyReference(const TupleReference& o) noexcept
1255   {
1256     // Must use same array, other array types may use different implementations.
1257     VTK_ITER_ASSERT(this->Array == o.Array, "Cannot copy reference objects between arrays.");
1258     this->NumComps = o.NumComps;
1259     this->TupleId = o.TupleId;
1260   }
1261 
1262   mutable ArrayType* Array;
1263   NumCompsType NumComps;
1264   TupleIdType TupleId;
1265 };
1266 
1267 //------------------------------------------------------------------------------
1268 // Const tuple iterator
1269 template <typename ArrayType, ComponentIdType TupleSize>
1270 struct ConstTupleIterator
1271 {
1272 private:
1273   static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
1274   static_assert(IsVtkDataArray<ArrayType>::value, "Invalid array type.");
1275 
1276   using NumCompsType = GenericTupleSize<TupleSize>;
1277 
1278 public:
1279   using iterator_category = std::random_access_iterator_tag;
1280   using value_type = ConstTupleReference<ArrayType, TupleSize>;
1281   using difference_type = TupleIdType;
1282   using pointer = ConstTupleReference<ArrayType, TupleSize>;
1283   using reference = ConstTupleReference<ArrayType, TupleSize>;
1284 
1285   VTK_ITER_INLINE
1286   ConstTupleIterator() noexcept = default;
1287 
1288   VTK_ITER_INLINE
1289   ConstTupleIterator(ArrayType* array, NumCompsType numComps, TupleIdType tupleId) noexcept
1290     : Ref(array, numComps, tupleId)
1291   {
1292     VTK_ITER_ASSERT(array != nullptr, "Invalid array.");
1293     VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components.");
1294     VTK_ITER_ASSERT(tupleId >= 0 && tupleId <= array->GetNumberOfTuples(),
1295       "Const tuple iterator at invalid tuple id.");
1296   }
1297 
1298   VTK_ITER_INLINE
1299   ConstTupleIterator(const TupleIterator<ArrayType, TupleSize>& o) noexcept
1300     : Ref{ o.Ref }
1301   {
1302   }
1303 
1304   VTK_ITER_INLINE
1305   ConstTupleIterator(const ConstTupleIterator& o) noexcept = default;
1306   VTK_ITER_INLINE
1307   ConstTupleIterator& operator=(const ConstTupleIterator& o) noexcept
1308   {
1309     this->Ref.CopyReference(o.Ref);
1310     return *this;
1311   }
1312 
1313   VTK_ITER_INLINE
1314   ConstTupleIterator& operator++() noexcept // prefix
1315   {
1316     ++this->Ref.TupleId;
1317     VTK_ITER_ASSERT(
1318       this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(),
1319       "Const tuple iterator at invalid component id.");
1320     return *this;
1321   }
1322 
1323   VTK_ITER_INLINE
1324   ConstTupleIterator operator++(int) noexcept // postfix
1325   {
1326     return ConstTupleIterator{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId++ };
1327   }
1328 
1329   VTK_ITER_INLINE
1330   ConstTupleIterator& operator--() noexcept // prefix
1331   {
1332     --this->Ref.TupleId;
1333     VTK_ITER_ASSERT(
1334       this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(),
1335       "Const tuple iterator at invalid component id.");
1336     return *this;
1337   }
1338 
1339   VTK_ITER_INLINE
1340   ConstTupleIterator operator--(int) noexcept // postfix
1341   {
1342     return ConstTupleIterator{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId-- };
1343   }
1344 
1345   VTK_ITER_INLINE
1346   reference operator[](difference_type i) noexcept
1347   {
1348     return reference{ this->GetArray(), this->GetNumComps(), this->GetTupleId() + i };
1349   }
1350 
1351   VTK_ITER_INLINE
1352   reference operator*() noexcept { return this->Ref; }
1353 
1354   VTK_ITER_INLINE
1355   pointer operator->() noexcept { return this->Ref; }
1356 
1357 #define VTK_TMP_MAKE_OPERATOR(OP)                                                                  \
1358   friend VTK_ITER_INLINE bool operator OP(                                                         \
1359     const ConstTupleIterator& lhs, const ConstTupleIterator& rhs) noexcept                         \
1360   {                                                                                                \
1361     VTK_ITER_ASSERT(                                                                               \
1362       lhs.GetArray() == rhs.GetArray(), "Cannot compare iterators from different arrays.");        \
1363     VTK_ITER_ASSUME(lhs.GetNumComps().value > 0);                                                  \
1364     VTK_ITER_ASSUME(lhs.GetNumComps().value == rhs.GetNumComps().value);                           \
1365     return lhs.GetTupleId() OP rhs.GetTupleId();                                                   \
1366   }
1367 
1368   VTK_TMP_MAKE_OPERATOR(==)
1369   VTK_TMP_MAKE_OPERATOR(!=)
1370   VTK_TMP_MAKE_OPERATOR(<)
1371   VTK_TMP_MAKE_OPERATOR(>)
1372   VTK_TMP_MAKE_OPERATOR(<=)
1373   VTK_TMP_MAKE_OPERATOR(>=)
1374 
1375 #undef VTK_TMP_MAKE_OPERATOR
1376 
1377   VTK_ITER_INLINE
1378   ConstTupleIterator& operator+=(difference_type offset) noexcept
1379   {
1380     this->Ref.TupleId += offset;
1381     VTK_ITER_ASSERT(
1382       this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(),
1383       "Const tuple iterator at invalid component id.");
1384     return *this;
1385   }
1386 
1387   friend VTK_ITER_INLINE ConstTupleIterator operator+(
1388     const ConstTupleIterator& it, difference_type offset) noexcept
1389   {
1390     return ConstTupleIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId() + offset };
1391   }
1392 
1393   friend VTK_ITER_INLINE ConstTupleIterator operator+(
1394     difference_type offset, const ConstTupleIterator& it) noexcept
1395   {
1396     return ConstTupleIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId() + offset };
1397   }
1398 
1399   VTK_ITER_INLINE
1400   ConstTupleIterator& operator-=(difference_type offset) noexcept
1401   {
1402     this->Ref.TupleId -= offset;
1403     VTK_ITER_ASSERT(
1404       this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(),
1405       "Const tuple iterator at invalid component id.");
1406     return *this;
1407   }
1408 
1409   friend VTK_ITER_INLINE ConstTupleIterator operator-(
1410     const ConstTupleIterator& it, difference_type offset) noexcept
1411   {
1412     return ConstTupleIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId() - offset };
1413   }
1414 
1415   friend VTK_ITER_INLINE difference_type operator-(
1416     const ConstTupleIterator& it1, const ConstTupleIterator& it2) noexcept
1417   {
1418     VTK_ITER_ASSERT(it1.GetArray() == it2.GetArray(),
1419       "Cannot do math with tuple iterators from different "
1420       "arrays.");
1421     return it1.GetTupleId() - it2.GetTupleId();
1422   }
1423 
1424   friend VTK_ITER_INLINE void swap(ConstTupleIterator& lhs, ConstTupleIterator& rhs) noexcept
1425   {
1426     // Different arrays may use different iterator implementations.
1427     VTK_ITER_ASSERT(
1428       lhs.GetArray() == rhs.GetArray(), "Cannot swap iterators from different arrays.");
1429 
1430     using std::swap;
1431     swap(lhs.GetTupleId(), rhs.GetTupleId());
1432   }
1433 
1434 private:
1435   VTK_ITER_INLINE
1436   ArrayType* GetArray() const noexcept { return this->Ref.Array; }
1437   VTK_ITER_INLINE
1438   ArrayType*& GetArray() noexcept { return this->Ref.Array; }
1439   VTK_ITER_INLINE
1440   NumCompsType GetNumComps() const noexcept { return this->Ref.NumComps; }
1441   VTK_ITER_INLINE
1442   NumCompsType& GetNumComps() noexcept { return this->Ref.NumComps; }
1443   VTK_ITER_INLINE
1444   TupleIdType GetTupleId() const noexcept { return this->Ref.TupleId; }
1445   VTK_ITER_INLINE
1446   TupleIdType& GetTupleId() noexcept { return this->Ref.TupleId; }
1447 
1448   ConstTupleReference<ArrayType, TupleSize> Ref;
1449 };
1450 
1451 //------------------------------------------------------------------------------
1452 // Tuple iterator
1453 template <typename ArrayType, ComponentIdType TupleSize>
1454 struct TupleIterator
1455 {
1456 private:
1457   static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
1458   static_assert(IsVtkDataArray<ArrayType>::value, "Invalid array type.");
1459 
1460   using NumCompsType = GenericTupleSize<TupleSize>;
1461 
1462 public:
1463   using iterator_category = std::random_access_iterator_tag;
1464   using value_type = TupleReference<ArrayType, TupleSize>;
1465   using difference_type = TupleIdType;
1466   using pointer = TupleReference<ArrayType, TupleSize>;
1467   using reference = TupleReference<ArrayType, TupleSize>;
1468 
1469   VTK_ITER_INLINE
1470   TupleIterator() noexcept = default;
1471 
1472   VTK_ITER_INLINE
1473   TupleIterator(ArrayType* array, NumCompsType numComps, TupleIdType tupleId) noexcept
1474     : Ref(array, numComps, tupleId)
1475   {
1476     VTK_ITER_ASSERT(array != nullptr, "Invalid array.");
1477     VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components.");
1478     VTK_ITER_ASSERT(
1479       tupleId >= 0 && tupleId <= array->GetNumberOfTuples(), "Tuple iterator at invalid tuple id.");
1480   }
1481 
1482   VTK_ITER_INLINE
1483   TupleIterator(const TupleIterator& o) noexcept = default;
1484 
1485   VTK_ITER_INLINE
1486   TupleIterator& operator=(const TupleIterator& o) noexcept
1487   {
1488     this->Ref.CopyReference(o.Ref);
1489     return *this;
1490   }
1491 
1492   VTK_ITER_INLINE
1493   TupleIterator& operator++() noexcept // prefix
1494   {
1495     ++this->Ref.TupleId;
1496     VTK_ITER_ASSERT(
1497       this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(),
1498       "Tuple iterator at invalid component id.");
1499     return *this;
1500   }
1501 
1502   VTK_ITER_INLINE
1503   TupleIterator operator++(int) noexcept // postfix
1504   {
1505     return TupleIterator{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId++ };
1506   }
1507 
1508   VTK_ITER_INLINE
1509   TupleIterator& operator--() noexcept // prefix
1510   {
1511     --this->Ref.TupleId;
1512     VTK_ITER_ASSERT(
1513       this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(),
1514       "Tuple iterator at invalid component id.");
1515     return *this;
1516   }
1517 
1518   VTK_ITER_INLINE
1519   TupleIterator operator--(int) noexcept // postfix
1520   {
1521     return TupleIterator{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId-- };
1522   }
1523 
1524   VTK_ITER_INLINE
1525   reference operator[](difference_type i) noexcept
1526   {
1527     return reference{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId + i };
1528   }
1529 
1530   VTK_ITER_INLINE
1531   reference operator*() noexcept { return this->Ref; }
1532 
1533   VTK_ITER_INLINE
1534   pointer& operator->() noexcept { return this->Ref; }
1535 
1536 #define VTK_TMP_MAKE_OPERATOR(OP)                                                                  \
1537   friend VTK_ITER_INLINE bool operator OP(                                                         \
1538     const TupleIterator& lhs, const TupleIterator& rhs) noexcept                                   \
1539   {                                                                                                \
1540     VTK_ITER_ASSERT(                                                                               \
1541       lhs.GetArray() == rhs.GetArray(), "Cannot compare iterators from different arrays.");        \
1542     VTK_ITER_ASSUME(lhs.GetNumComps().value > 0);                                                  \
1543     VTK_ITER_ASSUME(lhs.GetNumComps().value == rhs.GetNumComps().value);                           \
1544     return lhs.GetTupleId() OP rhs.GetTupleId();                                                   \
1545   }
1546 
1547   VTK_TMP_MAKE_OPERATOR(==)
1548   VTK_TMP_MAKE_OPERATOR(!=)
1549   VTK_TMP_MAKE_OPERATOR(<)
1550   VTK_TMP_MAKE_OPERATOR(>)
1551   VTK_TMP_MAKE_OPERATOR(<=)
1552   VTK_TMP_MAKE_OPERATOR(>=)
1553 
1554 #undef VTK_TMP_MAKE_OPERATOR
1555 
1556   VTK_ITER_INLINE
1557   TupleIterator& operator+=(difference_type offset) noexcept
1558   {
1559     this->Ref.TupleId += offset;
1560     VTK_ITER_ASSERT(
1561       this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(),
1562       "Tuple iterator at invalid component id.");
1563     return *this;
1564   }
1565 
1566   friend VTK_ITER_INLINE TupleIterator operator+(
1567     const TupleIterator& it, difference_type offset) noexcept
1568   {
1569     return TupleIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId() + offset };
1570   }
1571 
1572   friend VTK_ITER_INLINE TupleIterator operator+(
1573     difference_type offset, const TupleIterator& it) noexcept
1574   {
1575     return TupleIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId() + offset };
1576   }
1577 
1578   VTK_ITER_INLINE
1579   TupleIterator& operator-=(difference_type offset) noexcept
1580   {
1581     this->Ref.TupleId -= offset;
1582     VTK_ITER_ASSERT(
1583       this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(),
1584       "Tuple iterator at invalid component id.");
1585     return *this;
1586   }
1587 
1588   friend VTK_ITER_INLINE TupleIterator operator-(
1589     const TupleIterator& it, difference_type offset) noexcept
1590   {
1591     return TupleIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId() - offset };
1592   }
1593 
1594   friend VTK_ITER_INLINE difference_type operator-(
1595     const TupleIterator& it1, const TupleIterator& it2) noexcept
1596   {
1597     VTK_ITER_ASSERT(it1.GetArray() == it2.GetArray(),
1598       "Cannot do math with tuple iterators from different "
1599       "arrays.");
1600     return it1.GetTupleId() - it2.GetTupleId();
1601   }
1602 
1603   friend VTK_ITER_INLINE void swap(TupleIterator& lhs, TupleIterator& rhs) noexcept
1604   {
1605     // Different arrays may use different iterator implementations.
1606     VTK_ITER_ASSERT(
1607       lhs.GetArray() == rhs.GetArray(), "Cannot swap iterators from different arrays.");
1608 
1609     using std::swap;
1610     swap(lhs.GetTupleId(), rhs.GetTupleId());
1611   }
1612 
1613   friend struct ConstTupleIterator<ArrayType, TupleSize>;
1614   friend struct ConstTupleReference<ArrayType, TupleSize>;
1615 
1616 protected:
1617   VTK_ITER_INLINE
1618   ArrayType* GetArray() const noexcept { return this->Ref.Array; }
1619   VTK_ITER_INLINE
1620   ArrayType*& GetArray() noexcept { return this->Ref.Array; }
1621   VTK_ITER_INLINE
1622   NumCompsType GetNumComps() const noexcept { return this->Ref.NumComps; }
1623   VTK_ITER_INLINE
1624   NumCompsType& GetNumComps() noexcept { return this->Ref.NumComps; }
1625   VTK_ITER_INLINE
1626   TupleIdType GetTupleId() const noexcept { return this->Ref.TupleId; }
1627   VTK_ITER_INLINE
1628   TupleIdType& GetTupleId() noexcept { return this->Ref.TupleId; }
1629 
1630   TupleReference<ArrayType, TupleSize> Ref;
1631 };
1632 
1633 //------------------------------------------------------------------------------
1634 // Tuple range
1635 template <typename ArrayTypeT, ComponentIdType TupleSize>
1636 struct TupleRange
1637 {
1638 private:
1639   using NumCompsType = GenericTupleSize<TupleSize>;
1640   static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
1641   static_assert(IsVtkDataArray<ArrayTypeT>::value, "Invalid array type.");
1642 
1643 public:
1644   using ArrayType = ArrayTypeT;
1645   using APIType = GetAPIType<ArrayType>;
1646   using TupleIteratorType = TupleIterator<ArrayType, TupleSize>;
1647   using ConstTupleIteratorType = ConstTupleIterator<ArrayType, TupleSize>;
1648   using TupleReferenceType = TupleReference<ArrayType, TupleSize>;
1649   using ConstTupleReferenceType = ConstTupleReference<ArrayType, TupleSize>;
1650   using ComponentIteratorType = ComponentIterator<ArrayType, TupleSize>;
1651   using ConstComponentIteratorType = ConstComponentIterator<ArrayType, TupleSize>;
1652   using ComponentReferenceType = ComponentReference<ArrayType, TupleSize>;
1653   using ConstComponentReferenceType = ConstComponentReference<ArrayType, TupleSize>;
1654   using ComponentType = APIType;
1655 
1656   // May be DynamicTupleSize, or the actual tuple size.
1657   constexpr static ComponentIdType TupleSizeTag = TupleSize;
1658 
1659   using size_type = TupleIdType;
1660   using iterator = TupleIteratorType;
1661   using const_iterator = ConstTupleIteratorType;
1662   using reference = TupleReferenceType;
1663   using const_reference = ConstTupleReferenceType;
1664 
1665   VTK_ITER_INLINE
1666   TupleRange() noexcept = default;
1667 
1668   VTK_ITER_INLINE
1669   TupleRange(ArrayType* arr, TupleIdType beginTuple, TupleIdType endTuple) noexcept
1670     : Array(arr)
1671     , NumComps(arr)
1672     , BeginTuple(beginTuple)
1673     , EndTuple(endTuple)
1674   {
1675     assert(this->Array);
1676     assert(beginTuple >= 0 && beginTuple <= endTuple);
1677     assert(endTuple >= 0 && endTuple <= this->Array->GetNumberOfTuples());
1678   }
1679 
1680   VTK_ITER_INLINE
1681   TupleRange GetSubRange(TupleIdType beginTuple = 0, TupleIdType endTuple = -1) const noexcept
1682   {
1683     const TupleIdType realBegin = this->BeginTuple + beginTuple;
1684     const TupleIdType realEnd = endTuple >= 0 ? this->BeginTuple + endTuple : this->EndTuple;
1685 
1686     return TupleRange{ this->Array, realBegin, realEnd };
1687   }
1688 
1689   VTK_ITER_INLINE
1690   ArrayType* GetArray() const noexcept { return this->Array; }
1691   VTK_ITER_INLINE
1692   ComponentIdType GetTupleSize() const noexcept { return this->NumComps.value; }
1693   VTK_ITER_INLINE
1694   TupleIdType GetBeginTupleId() const noexcept { return this->BeginTuple; }
1695   VTK_ITER_INLINE
1696   TupleIdType GetEndTupleId() const noexcept { return this->EndTuple; }
1697 
1698   VTK_ITER_INLINE
1699   size_type size() const noexcept { return this->EndTuple - this->BeginTuple; }
1700 
1701   VTK_ITER_INLINE
1702   iterator begin() noexcept { return this->NewIter(this->BeginTuple); }
1703   VTK_ITER_INLINE
1704   iterator end() noexcept { return this->NewIter(this->EndTuple); }
1705 
1706   VTK_ITER_INLINE
1707   const_iterator begin() const noexcept { return this->NewCIter(this->BeginTuple); }
1708   VTK_ITER_INLINE
1709   const_iterator end() const noexcept { return this->NewCIter(this->EndTuple); }
1710 
1711   VTK_ITER_INLINE
1712   const_iterator cbegin() const noexcept { return this->NewCIter(this->BeginTuple); }
1713   VTK_ITER_INLINE
1714   const_iterator cend() const noexcept { return this->NewCIter(this->EndTuple); }
1715 
1716   VTK_ITER_INLINE
1717   reference operator[](size_type i) noexcept
1718   {
1719     return reference{ this->Array, this->NumComps, this->BeginTuple + i };
1720   }
1721 
1722   VTK_ITER_INLINE
1723   const_reference operator[](size_type i) const noexcept
1724   {
1725     return const_reference{ this->Array, this->NumComps, this->BeginTuple + i };
1726   }
1727 
1728 private:
1729   VTK_ITER_INLINE
1730   iterator NewIter(TupleIdType t) const { return iterator{ this->Array, this->NumComps, t }; }
1731 
1732   VTK_ITER_INLINE
1733   const_iterator NewCIter(TupleIdType t) const
1734   {
1735     return const_iterator{ this->Array, this->NumComps, t };
1736   }
1737 
1738   mutable ArrayType* Array{ nullptr };
1739   NumCompsType NumComps{};
1740   TupleIdType BeginTuple{ 0 };
1741   TupleIdType EndTuple{ 0 };
1742 };
1743 
1744 // Unimplemented, only used inside decltype in SelectTupleRange:
1745 template <typename ArrayType, ComponentIdType TupleSize>
1746 TupleRange<ArrayType, TupleSize> DeclareTupleRangeSpecialization(vtkDataArray*);
1747 
1748 } // end namespace detail
1749 } // end namespace vtk
1750 
1751 VTK_ITER_OPTIMIZE_END
1752 
1753 #endif // __VTK_WRAP__
1754 #endif // vtkDataArrayTupleRange_Generic_h
1755 
1756 // VTK-HeaderTest-Exclude: vtkDataArrayTupleRange_Generic.h
1757