/*========================================================================= Program: Visualization Toolkit Module: vtkDataArrayTupleRange_Generic.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /** * Generic implementation of value ranges and iterators, suitable for * vtkDataArray and all subclasses. */ #ifndef vtkDataArrayTupleRange_Generic_h #define vtkDataArrayTupleRange_Generic_h #include "vtkAssume.h" #include "vtkDataArrayAccessor.h" #include "vtkDataArrayMeta.h" #include #include #include #include VTK_ITER_OPTIMIZE_START namespace vtk { namespace detail { // Forward decs for friends/args template struct ConstComponentReference; template struct ComponentReference; template struct ConstComponentIterator; template struct ComponentIterator; template struct ConstTupleReference; template struct TupleReference; template struct ConstTupleIterator; template struct TupleIterator; template struct TupleRange; //------------------------------------------------------------------------------ // Const component reference template struct ConstComponentReference { private: static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); using NumCompsType = GenericTupleSize; using APIType = GetAPIType; public: using value_type = APIType; VTK_ITER_INLINE ConstComponentReference() noexcept : Array{ nullptr } , NumComps{} , TupleId{ 0 } , ComponentId{ 0 } { } VTK_ITER_INLINE ConstComponentReference( ArrayType* array, NumCompsType numComps, TupleIdType tuple, ComponentIdType comp) noexcept : Array{ array } , NumComps{ numComps } , TupleId{ tuple } , ComponentId{ comp } { VTK_ITER_ASSERT(array != nullptr, "Invalid array."); VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components."); VTK_ITER_ASSERT( tuple >= 0 && tuple <= array->GetNumberOfTuples(), "Invalid tuple accessed by iterator."); VTK_ITER_ASSERT(comp >= 0 && comp <= array->GetNumberOfComponents(), "Invalid component accessed by iterator."); } VTK_ITER_INLINE ConstComponentReference(const ComponentReference& o) : Array{ o.Array } , NumComps{ o.NumComps } , TupleId{ o.TupleId } , ComponentId{ o.ComponentId } { } VTK_ITER_INLINE ConstComponentReference(const ConstComponentReference& o) noexcept = default; VTK_ITER_INLINE ConstComponentReference(ConstComponentReference&& o) noexcept = default; VTK_ITER_INLINE ConstComponentReference& operator=(const ConstComponentReference& o) noexcept { VTK_ITER_ASSERT(!this->Array, "Const reference already initialized."); // Initialize the reference. this->Array = o.Array; this->NumComps = o.NumComps; this->TupleId = o.TupleId; this->ComponentId = o.ComponentId; } VTK_ITER_INLINE ConstComponentReference& operator=(ConstComponentReference&& o) noexcept { VTK_ITER_ASSERT(!this->Array, "Const reference already initialized."); // Initialize the reference. this->Array = std::move(o.Array); this->NumComps = std::move(o.NumComps); this->TupleId = std::move(o.TupleId); this->ComponentId = std::move(o.ComponentId); } VTK_ITER_INLINE operator APIType() const noexcept { VTK_ITER_ASSUME(this->NumComps.value > 0); VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->NumComps.value); vtkDataArrayAccessor acc{ this->Array }; return acc.Get(this->TupleId, this->ComponentId); } protected: mutable ArrayType* Array; NumCompsType NumComps; TupleIdType TupleId; ComponentIdType ComponentId; }; //------------------------------------------------------------------------------ // Component reference template struct ComponentReference { private: static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); using NumCompsType = GenericTupleSize; using APIType = GetAPIType; public: using value_type = APIType; VTK_ITER_INLINE ComponentReference() noexcept : Array{ nullptr } , NumComps{} , TupleId{ 0 } , ComponentId{ 0 } { } VTK_ITER_INLINE ComponentReference( ArrayType* array, NumCompsType numComps, TupleIdType tuple, ComponentIdType comp) noexcept : Array{ array } , NumComps{ numComps } , TupleId{ tuple } , ComponentId{ comp } { VTK_ITER_ASSERT(array != nullptr, "Invalid array."); VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components."); VTK_ITER_ASSERT( tuple >= 0 && tuple <= array->GetNumberOfTuples(), "Invalid tuple accessed by iterator."); VTK_ITER_ASSERT(comp >= 0 && comp <= array->GetNumberOfComponents(), "Invalid component accessed by iterator."); } VTK_ITER_INLINE ComponentReference(const ComponentReference& o) noexcept = default; VTK_ITER_INLINE ComponentReference(ComponentReference&& o) noexcept = default; VTK_ITER_INLINE ComponentReference operator=(const ComponentReference& o) noexcept { if (this->Array) { // Already initialized. Assign the value, not the reference return *this = static_cast(o); } else { // Initialize the reference. this->Array = o.Array; this->NumComps = o.NumComps; this->TupleId = o.TupleId; this->ComponentId = o.ComponentId; return *this; } } VTK_ITER_INLINE ComponentReference operator=(ComponentReference&& o) noexcept { if (this->Array) { // Already initialized. Assign the value, not the reference return *this = std::move(static_cast(o)); } else { // Initialize the reference. this->Array = std::move(o.Array); this->NumComps = std::move(o.NumComps); this->TupleId = std::move(o.TupleId); this->ComponentId = std::move(o.ComponentId); return *this; } } template VTK_ITER_INLINE ComponentReference operator=(const ComponentReference& o) noexcept { // Always copy the value for different reference types: const APIType tmp = o; return *this = std::move(tmp); } VTK_ITER_INLINE operator APIType() const noexcept { VTK_ITER_ASSUME(this->NumComps.value > 0); VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->NumComps.value); vtkDataArrayAccessor acc{ this->Array }; return acc.Get(this->TupleId, this->ComponentId); } VTK_ITER_INLINE ComponentReference operator=(APIType val) noexcept { VTK_ITER_ASSUME(this->NumComps.value > 0); VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->NumComps.value); vtkDataArrayAccessor acc{ this->Array }; acc.Set(this->TupleId, this->ComponentId, val); return *this; } friend VTK_ITER_INLINE void swap(ComponentReference lhs, ComponentReference rhs) noexcept { // Swap values, not references: APIType tmp = std::move(static_cast(lhs)); lhs = std::move(static_cast(rhs)); rhs = std::move(tmp); } template friend VTK_ITER_INLINE void swap( ComponentReference lhs, ComponentReference rhs) noexcept { // Swap values, not references: using OAPIType = GetAPIType; static_assert( std::is_same::value, "Cannot swap components with different types."); APIType tmp = std::move(static_cast(lhs)); lhs = std::move(static_cast(rhs)); rhs = std::move(tmp); } friend VTK_ITER_INLINE void swap(ComponentReference lhs, APIType& rhs) noexcept { APIType tmp = std::move(static_cast(lhs)); lhs = std::move(rhs); rhs = std::move(tmp); } friend VTK_ITER_INLINE void swap(APIType& lhs, ComponentReference rhs) noexcept { APIType tmp = std::move(lhs); lhs = std::move(static_cast(rhs)); rhs = std::move(tmp); } VTK_ITER_INLINE ComponentReference operator++() noexcept // prefix { const APIType newVal = *this + 1; *this = newVal; return *this; } VTK_ITER_INLINE APIType operator++(int) noexcept // postfix { const APIType retVal = *this; *this = *this + 1; return retVal; } VTK_ITER_INLINE ComponentReference operator--() noexcept // prefix { const APIType newVal = *this - 1; *this = newVal; return *this; } VTK_ITER_INLINE APIType operator--(int) noexcept // postfix { const APIType retVal = *this; *this = *this - 1; return retVal; } #define VTK_REF_OP_OVERLOADS(Op, ImplOp) \ friend VTK_ITER_INLINE ComponentReference operator Op( \ ComponentReference lhs, APIType val) noexcept \ { \ const APIType newVal = lhs ImplOp val; \ lhs = newVal; \ return lhs; \ } \ friend VTK_ITER_INLINE ComponentReference operator Op( \ ComponentReference lhs, ComponentReference val) noexcept \ { \ const APIType newVal = lhs ImplOp val; \ lhs = newVal; \ return lhs; \ } \ friend VTK_ITER_INLINE APIType& operator Op(APIType& lhs, ComponentReference val) noexcept \ { \ const APIType newVal = lhs ImplOp val; \ lhs = newVal; \ return lhs; \ } VTK_REF_OP_OVERLOADS(+=, +) VTK_REF_OP_OVERLOADS(-=, -) VTK_REF_OP_OVERLOADS(*=, *) VTK_REF_OP_OVERLOADS(/=, /) #undef VTK_REF_OP_OVERLOADS friend struct ConstComponentReference; friend struct ComponentIterator; protected: VTK_ITER_INLINE void CopyReference(const ComponentReference& o) noexcept { this->Array = o.Array; this->NumComps = o.NumComps; this->TupleId = o.TupleId; this->ComponentId = o.ComponentId; } mutable ArrayType* Array; NumCompsType NumComps; TupleIdType TupleId; ComponentIdType ComponentId; }; //------------------------------------------------------------------------------ // Const component iterator template struct ConstComponentIterator { private: static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); using NumCompsType = GenericTupleSize; public: using iterator_category = std::random_access_iterator_tag; using value_type = GetAPIType; using difference_type = ComponentIdType; using pointer = void; using reference = ConstComponentReference; VTK_ITER_INLINE ConstComponentIterator() noexcept : Array{ nullptr } , TupleId{ 0 } , ComponentId{ 0 } { } VTK_ITER_INLINE ConstComponentIterator( ArrayType* array, NumCompsType numComps, TupleIdType tupleId, ComponentIdType comp) noexcept : Array(array) , NumComps(numComps) , TupleId(tupleId) , ComponentId(comp) { VTK_ITER_ASSERT(array != nullptr, "Invalid array."); VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components."); VTK_ITER_ASSERT(tupleId >= 0 && tupleId <= array->GetNumberOfTuples(), "Const component iterator at invalid tuple id."); VTK_ITER_ASSERT(comp >= 0 && comp <= this->NumComps.value, "Const component iterator at invalid component id."); } VTK_ITER_INLINE ConstComponentIterator(const ComponentIterator& o) noexcept : Array{ o.GetArray() } , NumComps{ o.GetNumComps() } , TupleId{ o.GetTupleId() } , ComponentId{ o.GetComponentId() } { } VTK_ITER_INLINE ConstComponentIterator(const ConstComponentIterator& o) noexcept = default; VTK_ITER_INLINE ConstComponentIterator& operator=(const ConstComponentIterator& o) noexcept = default; VTK_ITER_INLINE ConstComponentIterator& operator++() noexcept // prefix { ++this->ComponentId; VTK_ITER_ASSERT(this->ComponentId >= 0 && this->ComponentId <= this->NumComps.value, "Const component iterator at invalid component id."); return *this; } VTK_ITER_INLINE ConstComponentIterator operator++(int) noexcept // postfix { return ConstComponentIterator{ this->Array, this->NumComps, this->TupleId, this->ComponentId++ }; } VTK_ITER_INLINE ConstComponentIterator& operator--() noexcept // prefix { --this->ComponentId; VTK_ITER_ASSERT(this->ComponentId >= 0 && this->ComponentId <= this->NumComps.value, "Const component iterator at invalid component id."); return *this; } VTK_ITER_INLINE ConstComponentIterator operator--(int) noexcept // postfix { return ConstComponentIterator{ this->Array, this->NumComps, this->TupleId, this->ComponentId-- }; } VTK_ITER_INLINE reference operator[](difference_type i) const noexcept { return reference{ this->Array, this->NumComps, this->TupleId, this->ComponentId + i }; } VTK_ITER_INLINE reference operator*() const noexcept { return reference{ this->Array, this->NumComps, this->TupleId, this->ComponentId }; } #define VTK_TMP_MAKE_OPERATOR(OP) \ friend VTK_ITER_INLINE bool operator OP( \ const ConstComponentIterator& lhs, const ConstComponentIterator& rhs) noexcept \ { \ VTK_ITER_ASSERT(lhs.Array == rhs.Array, "Mismatched arrays in iterator comparison."); \ VTK_ITER_ASSERT(lhs.TupleId == rhs.TupleId, "Mismatched tuple ids in iterator comparison."); \ VTK_ITER_ASSUME(lhs.NumComps.value > 0); \ VTK_ITER_ASSUME(lhs.NumComps.value == rhs.NumComps.value); \ return lhs.ComponentId OP rhs.ComponentId; \ } VTK_TMP_MAKE_OPERATOR(==) VTK_TMP_MAKE_OPERATOR(!=) VTK_TMP_MAKE_OPERATOR(<) VTK_TMP_MAKE_OPERATOR(>) VTK_TMP_MAKE_OPERATOR(<=) VTK_TMP_MAKE_OPERATOR(>=) #undef VTK_TMP_MAKE_OPERATOR VTK_ITER_INLINE ConstComponentIterator& operator+=(difference_type offset) noexcept { this->ComponentId += offset; VTK_ITER_ASSERT(this->ComponentId >= 0 && this->ComponentId <= this->NumComps.value, "Const component iterator at invalid component id."); return *this; } friend VTK_ITER_INLINE ConstComponentIterator operator+( const ConstComponentIterator& it, difference_type offset) noexcept { return ConstComponentIterator{ it.Array, it.NumComps, it.TupleId, it.ComponentId + offset }; } friend VTK_ITER_INLINE ConstComponentIterator operator+( difference_type offset, const ConstComponentIterator& it) noexcept { return ConstComponentIterator{ it.Array, it.NumComps, it.TupleId, it.ComponentId + offset }; } VTK_ITER_INLINE ConstComponentIterator& operator-=(difference_type offset) noexcept { this->ComponentId -= offset; VTK_ITER_ASSERT(this->ComponentId >= 0 && this->ComponentId <= this->NumComps.value, "Const component iterator at invalid component id."); return *this; } friend VTK_ITER_INLINE ConstComponentIterator operator-( const ConstComponentIterator& it, difference_type offset) noexcept { return ConstComponentIterator{ it.Array, it.NumComps, it.TupleId, it.ComponentId - offset }; } friend VTK_ITER_INLINE difference_type operator-( const ConstComponentIterator& it1, const ConstComponentIterator& it2) noexcept { VTK_ITER_ASSERT(it1.Array == it2.Array, "Cannot do math with iterators from different arrays."); VTK_ITER_ASSERT(it1.TupleId == it2.TupleId, "Cannot do math with component iterators from different " "tuples."); return it1.ComponentId - it2.ComponentId; } friend VTK_ITER_INLINE void swap( ConstComponentIterator& lhs, ConstComponentIterator& rhs) noexcept { // Different arrays may use different iterator implementations. VTK_ITER_ASSERT(lhs.Array == rhs.Array, "Cannot swap iterators from different arrays."); using std::swap; swap(lhs.TupleId, rhs.TupleId); swap(lhs.ComponentId, rhs.ComponentId); } private: mutable ArrayType* Array; NumCompsType NumComps; TupleIdType TupleId; ComponentIdType ComponentId; }; //------------------------------------------------------------------------------ // Component iterator template struct ComponentIterator { private: static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); using NumCompsType = GenericTupleSize; using APIType = GetAPIType; public: using iterator_category = std::random_access_iterator_tag; using value_type = APIType; using difference_type = ComponentIdType; using pointer = ComponentReference; using reference = ComponentReference; VTK_ITER_INLINE ComponentIterator() noexcept = default; VTK_ITER_INLINE ComponentIterator( ArrayType* array, NumCompsType numComps, TupleIdType tupleId, ComponentIdType comp) noexcept : Ref(array, numComps, tupleId, comp) { VTK_ITER_ASSERT(array != nullptr, "Invalid array."); VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components."); VTK_ITER_ASSERT(tupleId >= 0 && tupleId <= array->GetNumberOfTuples(), "Component iterator at invalid tuple id."); VTK_ITER_ASSERT( comp >= 0 && comp <= numComps.value, "Component iterator at invalid component id."); } VTK_ITER_INLINE ComponentIterator(const ComponentIterator& o) noexcept = default; VTK_ITER_INLINE ComponentIterator& operator=(const ComponentIterator& o) noexcept { this->Ref.CopyReference(o.Ref); return *this; } VTK_ITER_INLINE ComponentIterator& operator++() noexcept // prefix { ++this->Ref.ComponentId; VTK_ITER_ASSERT(this->Ref.ComponentId >= 0 && this->Ref.ComponentId <= this->Ref.NumComps.value, "Component iterator at invalid component id."); return *this; } VTK_ITER_INLINE ComponentIterator operator++(int) noexcept // postfix { return ComponentIterator{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId, this->Ref.ComponentId++ }; } VTK_ITER_INLINE ComponentIterator& operator--() noexcept // prefix { --this->Ref.ComponentId; VTK_ITER_ASSERT(this->Ref.ComponentId >= 0 && this->Ref.ComponentId <= this->Ref.NumComps.value, "Component iterator at invalid component id."); return *this; } VTK_ITER_INLINE ComponentIterator operator--(int) noexcept // postfix { return ComponentIterator{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId, this->Ref.ComponentId-- }; } VTK_ITER_INLINE reference operator[](difference_type i) const noexcept { return reference{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId, this->Ref.ComponentId + i }; } VTK_ITER_INLINE reference operator*() const noexcept { return this->Ref; } VTK_ITER_INLINE const pointer& operator->() const noexcept { return this->Ref; } #define VTK_TMP_MAKE_OPERATOR(OP) \ friend VTK_ITER_INLINE bool operator OP( \ const ComponentIterator& lhs, const ComponentIterator& rhs) noexcept \ { \ VTK_ITER_ASSERT( \ lhs.GetArray() == rhs.GetArray(), "Mismatched arrays in iterator comparison."); \ VTK_ITER_ASSERT( \ lhs.GetTupleId() == rhs.GetTupleId(), "Mismatched tuple ids in iterator comparison."); \ VTK_ITER_ASSUME(lhs.GetNumComps().value > 0); \ VTK_ITER_ASSUME(lhs.GetNumComps().value == rhs.GetNumComps().value); \ return lhs.GetComponentId() OP rhs.GetComponentId(); \ } VTK_TMP_MAKE_OPERATOR(==) VTK_TMP_MAKE_OPERATOR(!=) VTK_TMP_MAKE_OPERATOR(<) VTK_TMP_MAKE_OPERATOR(>) VTK_TMP_MAKE_OPERATOR(<=) VTK_TMP_MAKE_OPERATOR(>=) #undef VTK_TMP_MAKE_OPERATOR VTK_ITER_INLINE ComponentIterator& operator+=(difference_type offset) noexcept { this->Ref.ComponentId += offset; VTK_ITER_ASSERT(this->Ref.ComponentId >= 0 && this->Ref.ComponentId <= this->Ref.NumComps.value, "Component iterator at invalid component id."); return *this; } friend VTK_ITER_INLINE ComponentIterator operator+( const ComponentIterator& it, difference_type offset) noexcept { return ComponentIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId(), it.GetComponentId() + offset }; } friend VTK_ITER_INLINE ComponentIterator operator+( difference_type offset, const ComponentIterator& it) noexcept { return ComponentIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId(), it.GetComponentId() + offset }; } VTK_ITER_INLINE ComponentIterator& operator-=(difference_type offset) noexcept { this->Ref.ComponentId -= offset; VTK_ITER_ASSERT(this->Ref.ComponentId >= 0 && this->Ref.ComponentId <= this->Ref.NumComps.value, "Component iterator at invalid component id."); return *this; } friend VTK_ITER_INLINE ComponentIterator operator-( const ComponentIterator& it, difference_type offset) noexcept { return ComponentIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId(), it.GetComponentId() - offset }; } friend VTK_ITER_INLINE difference_type operator-( const ComponentIterator& it1, const ComponentIterator& it2) noexcept { VTK_ITER_ASSERT(it1.GetArray() == it2.GetArray(), "Cannot do math with component iterators from different " "arrays."); VTK_ITER_ASSERT(it1.GetTupleId() == it2.GetTupleId(), "Cannot do math with component iterators from different " "tuples."); return it1.GetComponentId() - it2.GetComponentId(); } friend VTK_ITER_INLINE void swap(ComponentIterator& lhs, ComponentIterator& rhs) noexcept { // Different arrays may use different iterator implementations. VTK_ITER_ASSERT( lhs.GetArray() == rhs.GetArray(), "Cannot swap iterators from different arrays."); using std::swap; swap(lhs.GetTupleId(), rhs.GetTupleId()); swap(lhs.GetComponentId(), rhs.GetComponentId()); } friend struct ConstComponentIterator; protected: // Needed for access from friend functions. We could just store the array // and ID here instead of the ref, but meh. ArrayType* GetArray() const noexcept { return this->Ref.Array; } TupleIdType& GetTupleId() noexcept { return this->Ref.TupleId; } const TupleIdType& GetTupleId() const noexcept { return this->Ref.TupleId; } ComponentIdType& GetComponentId() noexcept { return this->Ref.ComponentId; } const ComponentIdType& GetComponentId() const noexcept { return this->Ref.ComponentId; } NumCompsType& GetNumComps() noexcept { return this->Ref.NumComps; } const NumCompsType& GetNumComps() const noexcept { return this->Ref.NumComps; } ComponentReference Ref; }; //------------------------------------------------------------------------------ // Const tuple reference template struct ConstTupleReference { private: static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); using NumCompsType = GenericTupleSize; using APIType = GetAPIType; public: using size_type = ComponentIdType; using value_type = APIType; using iterator = ConstComponentIterator; using const_iterator = ConstComponentIterator; using const_reference = ConstComponentReference; VTK_ITER_INLINE ConstTupleReference() noexcept : Array(nullptr) , TupleId(0) { } VTK_ITER_INLINE ConstTupleReference(ArrayType* array, NumCompsType numComps, TupleIdType tupleId) noexcept : Array(array) , NumComps(numComps) , TupleId(tupleId) { VTK_ITER_ASSERT(array != nullptr, "Invalid array."); VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components."); VTK_ITER_ASSERT(tupleId >= 0 && tupleId <= array->GetNumberOfTuples(), "Const tuple reference at invalid tuple id."); } VTK_ITER_INLINE ConstTupleReference(const TupleReference& o) noexcept : Array{ o.Array } , NumComps{ o.NumComps } , TupleId{ o.TupleId } { } VTK_ITER_INLINE ConstTupleReference(const ConstTupleReference&) noexcept = default; VTK_ITER_INLINE ConstTupleReference(ConstTupleReference&&) noexcept = default; // Allow this type to masquerade as a pointer, so that tupleIiter->foo works. VTK_ITER_INLINE ConstTupleReference* operator->() noexcept { return this; } VTK_ITER_INLINE const ConstTupleReference* operator->() const noexcept { return this; } // Caller must ensure that there are size() elements in array. VTK_ITER_INLINE void GetTuple(APIType* tuple) const noexcept { VTK_ITER_ASSUME(this->NumComps.value > 0); VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->NumComps.value); vtkDataArrayAccessor acc{ this->Array }; acc.Get(this->TupleId, tuple); } // skips some runtime checks when both sizes are fixed: template VTK_ITER_INLINE EnableIfStaticTupleSizes operator==( const TupleReference& other) const noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when comparing tuples."); // SFINAE guarantees that the tuple sizes are not dynamic in this overload: static_assert(TupleSize == OSize, "Cannot compare tuples with different sizes."); return std::equal(this->cbegin(), this->cend(), other.cbegin()); } // Needs a runtime check: template VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic operator==( const TupleReference& other) const noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when comparing tuples."); VTK_ITER_ASSERT( other.size() == this->NumComps.value, "Cannot compare tuples with different sizes."); return std::equal(this->cbegin(), this->cend(), other.cbegin()); } // skips some runtime checks when both sizes are fixed: template VTK_ITER_INLINE EnableIfStaticTupleSizes operator==( const ConstTupleReference& other) const noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when comparing tuples."); // SFINAE guarantees that the tuple sizes are not dynamic in this overload: static_assert(TupleSize == OSize, "Cannot compare tuples with different sizes."); return std::equal(this->cbegin(), this->cend(), other.cbegin()); } // Needs a runtime check: template VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic operator==( const ConstTupleReference& other) const noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when comparing tuples."); VTK_ITER_ASSERT( other.size() == this->NumComps.value, "Cannot compare tuples with different sizes."); return std::equal(this->cbegin(), this->cend(), other.cbegin()); } template VTK_ITER_INLINE bool operator!=(const TupleReference& o) const noexcept { return !(*this == o); } template VTK_ITER_INLINE bool operator!=(const ConstTupleReference& o) const noexcept { return !(*this == o); } VTK_ITER_INLINE const_reference operator[](size_type i) const noexcept { return const_reference{ this->Array, this->NumComps, this->TupleId, i }; } VTK_ITER_INLINE size_type size() const noexcept { return this->NumComps.value; } VTK_ITER_INLINE const_iterator begin() const noexcept { return this->NewConstIterator(0); } VTK_ITER_INLINE const_iterator end() const noexcept { return this->NewConstIterator(this->NumComps.value); } VTK_ITER_INLINE const_iterator cbegin() const noexcept { return this->NewConstIterator(0); } VTK_ITER_INLINE const_iterator cend() const noexcept { return this->NewConstIterator(this->NumComps.value); } friend struct ConstTupleIterator; protected: // Intentionally hidden: VTK_ITER_INLINE ConstTupleReference& operator=(const ConstTupleReference&) noexcept = default; VTK_ITER_INLINE const_iterator NewConstIterator(ComponentIdType comp) const noexcept { VTK_ITER_ASSUME(this->NumComps.value > 0); return const_iterator{ this->Array, this->NumComps, this->TupleId, comp }; } VTK_ITER_INLINE void CopyReference(const ConstTupleReference& o) noexcept { // Must use same array, other array types may use different implementations. VTK_ITER_ASSERT(this->Array == o.Array, "Cannot copy reference objects between arrays."); this->NumComps = o.NumComps; this->TupleId = o.TupleId; } mutable ArrayType* Array; NumCompsType NumComps; TupleIdType TupleId; }; //------------------------------------------------------------------------------ // Tuple reference template struct TupleReference { private: static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); using NumCompsType = GenericTupleSize; using APIType = GetAPIType; public: using size_type = ComponentIdType; using value_type = APIType; using iterator = ComponentIterator; using const_iterator = ConstComponentIterator; using reference = ComponentReference; using const_reference = ConstComponentReference; VTK_ITER_INLINE TupleReference() noexcept : Array(nullptr) , TupleId(0) { } VTK_ITER_INLINE TupleReference(ArrayType* array, NumCompsType numComps, TupleIdType tupleId) noexcept : Array(array) , NumComps(numComps) , TupleId(tupleId) { VTK_ITER_ASSERT(array != nullptr, "Invalid array."); VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components."); VTK_ITER_ASSERT(tupleId >= 0 && tupleId <= array->GetNumberOfTuples(), "Tuple reference at invalid tuple id."); } VTK_ITER_INLINE TupleReference(const TupleReference&) = default; VTK_ITER_INLINE TupleReference(TupleReference&&) = default; // Allow this type to masquerade as a pointer, so that tupleIiter->foo works. VTK_ITER_INLINE TupleReference* operator->() noexcept { return this; } VTK_ITER_INLINE const TupleReference* operator->() const noexcept { return this; } // Caller must ensure that there are size() elements in array. VTK_ITER_INLINE void GetTuple(APIType* tuple) const noexcept { VTK_ITER_ASSUME(this->NumComps.value > 0); VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->NumComps.value); vtkDataArrayAccessor acc{ this->Array }; acc.Get(this->TupleId, tuple); } // Caller must ensure that there are size() elements in array. VTK_ITER_INLINE void SetTuple(const APIType* tuple) noexcept { VTK_ITER_ASSUME(this->NumComps.value > 0); VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->NumComps.value); vtkDataArrayAccessor acc{ this->Array }; acc.Set(this->TupleId, tuple); } VTK_ITER_INLINE TupleReference& operator=(const TupleReference& other) noexcept { std::copy_n(other.cbegin(), this->NumComps.value, this->begin()); return *this; } // skips some runtime checks when both sizes are fixed: template VTK_ITER_INLINE EnableIfStaticTupleSizes operator=( const TupleReference& other) noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when assigning tuples."); // SFINAE guarantees that the tuple sizes are not dynamic in this overload: static_assert(TupleSize == OSize, "Cannot assign tuples with different sizes."); std::copy_n(other.cbegin(), OSize, this->begin()); return *this; } // Needs a runtime check: template VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic operator=( const TupleReference& other) noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when assigning tuples."); VTK_ITER_ASSERT( other.size() == this->NumComps.value, "Cannot assign tuples with different sizes."); std::copy_n(other.cbegin(), this->NumComps.value, this->begin()); return *this; } // skips some runtime checks when both sizes are fixed: template VTK_ITER_INLINE EnableIfStaticTupleSizes operator=( const ConstTupleReference& other) noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when assigning tuples."); // SFINAE guarantees that the tuple sizes are not dynamic in this overload: static_assert(TupleSize == OSize, "Cannot assign tuples with different sizes."); std::copy_n(other.cbegin(), OSize, this->begin()); return *this; } // Needs a runtime check: template VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic operator=( const ConstTupleReference& other) noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when assigning tuples."); VTK_ITER_ASSERT( other.size() == this->NumComps.value, "Cannot assign tuples with different sizes."); std::copy_n(other.cbegin(), this->NumComps.value, this->begin()); return *this; } // skips some runtime checks when both sizes are fixed: template VTK_ITER_INLINE EnableIfStaticTupleSizes operator==( const TupleReference& other) const noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when comparing tuples."); // SFINAE guarantees that the tuple sizes are not dynamic in this overload: static_assert(TupleSize == OSize, "Cannot compare tuples with different sizes."); return std::equal(this->cbegin(), this->cend(), other.cbegin()); } // Needs a runtime check: template VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic operator==( const TupleReference& other) const noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when comparing tuples."); VTK_ITER_ASSERT( other.size() == this->NumComps.value, "Cannot compare tuples with different sizes."); return std::equal(this->cbegin(), this->cend(), other.cbegin()); } // skips some runtime checks when both sizes are fixed: template VTK_ITER_INLINE EnableIfStaticTupleSizes operator==( const ConstTupleReference& other) const noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when comparing tuples."); // SFINAE guarantees that the tuple sizes are not dynamic in this overload: static_assert(TupleSize == OSize, "Cannot compare tuples with different sizes."); return std::equal(this->cbegin(), this->cend(), other.cbegin()); } // Needs a runtime check: template VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic operator==( const ConstTupleReference& other) const noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when comparing tuples."); VTK_ITER_ASSERT( other.size() == this->NumComps.value, "Cannot compare tuples with different sizes."); return std::equal(this->cbegin(), this->cend(), other.cbegin()); } template VTK_ITER_INLINE bool operator!=(const TupleReference& o) const noexcept { return !(*this == o); } template VTK_ITER_INLINE bool operator!=(const ConstTupleReference& o) const noexcept { return !(*this == o); } // skips some runtime checks: template VTK_ITER_INLINE EnableIfStaticTupleSizes swap( TupleReference other) noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when swapping tuples."); // SFINAE guarantees that the tuple sizes are not dynamic in this overload: static_assert(TupleSize == OSize, "Cannot swap tuples with different sizes."); std::swap_ranges(this->begin(), this->end(), other.begin()); } // Needs a runtime check: template VTK_ITER_INLINE EnableIfEitherTupleSizeIsDynamic swap( TupleReference other) noexcept { // Check that types are convertible: using OAPIType = GetAPIType; static_assert( (std::is_convertible{}), "Incompatible types when swapping tuples."); VTK_ITER_ASSERT( other.size() == this->NumComps.value, "Cannot swap tuples with different sizes."); std::swap_ranges(this->begin(), this->end(), other.begin()); } friend VTK_ITER_INLINE void swap(TupleReference a, TupleReference b) noexcept { a.swap(b); } template friend VTK_ITER_INLINE void swap(TupleReference a, TupleReference b) noexcept { a.swap(b); } VTK_ITER_INLINE reference operator[](size_type i) noexcept { return reference{ this->Array, this->NumComps, this->TupleId, i }; } VTK_ITER_INLINE const_reference operator[](size_type i) const noexcept { // Let the reference type do the lookup during implicit conversion. return const_reference{ this->Array, this->NumComps, this->TupleId, i }; } VTK_ITER_INLINE void fill(const value_type& v) noexcept { std::fill(this->begin(), this->end(), v); } VTK_ITER_INLINE size_type size() const noexcept { return this->NumComps.value; } VTK_ITER_INLINE iterator begin() noexcept { return this->NewIterator(0); } VTK_ITER_INLINE iterator end() noexcept { return this->NewIterator(this->NumComps.value); } VTK_ITER_INLINE const_iterator begin() const noexcept { return this->NewConstIterator(0); } VTK_ITER_INLINE const_iterator end() const noexcept { return this->NewConstIterator(this->NumComps.value); } VTK_ITER_INLINE const_iterator cbegin() const noexcept { return this->NewConstIterator(0); } VTK_ITER_INLINE const_iterator cend() const noexcept { return this->NewConstIterator(this->NumComps.value); } friend struct ConstTupleReference; friend struct TupleIterator; protected: VTK_ITER_INLINE iterator NewIterator(ComponentIdType comp) const noexcept { VTK_ITER_ASSUME(this->NumComps.value > 0); return iterator{ this->Array, this->NumComps, this->TupleId, comp }; } VTK_ITER_INLINE const_iterator NewConstIterator(ComponentIdType comp) const noexcept { VTK_ITER_ASSUME(this->NumComps.value > 0); return const_iterator{ this->Array, this->NumComps, this->TupleId, comp }; } VTK_ITER_INLINE void CopyReference(const TupleReference& o) noexcept { // Must use same array, other array types may use different implementations. VTK_ITER_ASSERT(this->Array == o.Array, "Cannot copy reference objects between arrays."); this->NumComps = o.NumComps; this->TupleId = o.TupleId; } mutable ArrayType* Array; NumCompsType NumComps; TupleIdType TupleId; }; //------------------------------------------------------------------------------ // Const tuple iterator template struct ConstTupleIterator { private: static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); using NumCompsType = GenericTupleSize; public: using iterator_category = std::random_access_iterator_tag; using value_type = ConstTupleReference; using difference_type = TupleIdType; using pointer = ConstTupleReference; using reference = ConstTupleReference; VTK_ITER_INLINE ConstTupleIterator() noexcept = default; VTK_ITER_INLINE ConstTupleIterator(ArrayType* array, NumCompsType numComps, TupleIdType tupleId) noexcept : Ref(array, numComps, tupleId) { VTK_ITER_ASSERT(array != nullptr, "Invalid array."); VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components."); VTK_ITER_ASSERT(tupleId >= 0 && tupleId <= array->GetNumberOfTuples(), "Const tuple iterator at invalid tuple id."); } VTK_ITER_INLINE ConstTupleIterator(const TupleIterator& o) noexcept : Ref{ o.Ref } { } VTK_ITER_INLINE ConstTupleIterator(const ConstTupleIterator& o) noexcept = default; VTK_ITER_INLINE ConstTupleIterator& operator=(const ConstTupleIterator& o) noexcept { this->Ref.CopyReference(o.Ref); return *this; } VTK_ITER_INLINE ConstTupleIterator& operator++() noexcept // prefix { ++this->Ref.TupleId; VTK_ITER_ASSERT( this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(), "Const tuple iterator at invalid component id."); return *this; } VTK_ITER_INLINE ConstTupleIterator operator++(int) noexcept // postfix { return ConstTupleIterator{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId++ }; } VTK_ITER_INLINE ConstTupleIterator& operator--() noexcept // prefix { --this->Ref.TupleId; VTK_ITER_ASSERT( this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(), "Const tuple iterator at invalid component id."); return *this; } VTK_ITER_INLINE ConstTupleIterator operator--(int) noexcept // postfix { return ConstTupleIterator{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId-- }; } VTK_ITER_INLINE reference operator[](difference_type i) noexcept { return reference{ this->GetArray(), this->GetNumComps(), this->GetTupleId() + i }; } VTK_ITER_INLINE reference operator*() noexcept { return this->Ref; } VTK_ITER_INLINE pointer operator->() noexcept { return this->Ref; } #define VTK_TMP_MAKE_OPERATOR(OP) \ friend VTK_ITER_INLINE bool operator OP( \ const ConstTupleIterator& lhs, const ConstTupleIterator& rhs) noexcept \ { \ VTK_ITER_ASSERT( \ lhs.GetArray() == rhs.GetArray(), "Cannot compare iterators from different arrays."); \ VTK_ITER_ASSUME(lhs.GetNumComps().value > 0); \ VTK_ITER_ASSUME(lhs.GetNumComps().value == rhs.GetNumComps().value); \ return lhs.GetTupleId() OP rhs.GetTupleId(); \ } VTK_TMP_MAKE_OPERATOR(==) VTK_TMP_MAKE_OPERATOR(!=) VTK_TMP_MAKE_OPERATOR(<) VTK_TMP_MAKE_OPERATOR(>) VTK_TMP_MAKE_OPERATOR(<=) VTK_TMP_MAKE_OPERATOR(>=) #undef VTK_TMP_MAKE_OPERATOR VTK_ITER_INLINE ConstTupleIterator& operator+=(difference_type offset) noexcept { this->Ref.TupleId += offset; VTK_ITER_ASSERT( this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(), "Const tuple iterator at invalid component id."); return *this; } friend VTK_ITER_INLINE ConstTupleIterator operator+( const ConstTupleIterator& it, difference_type offset) noexcept { return ConstTupleIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId() + offset }; } friend VTK_ITER_INLINE ConstTupleIterator operator+( difference_type offset, const ConstTupleIterator& it) noexcept { return ConstTupleIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId() + offset }; } VTK_ITER_INLINE ConstTupleIterator& operator-=(difference_type offset) noexcept { this->Ref.TupleId -= offset; VTK_ITER_ASSERT( this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(), "Const tuple iterator at invalid component id."); return *this; } friend VTK_ITER_INLINE ConstTupleIterator operator-( const ConstTupleIterator& it, difference_type offset) noexcept { return ConstTupleIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId() - offset }; } friend VTK_ITER_INLINE difference_type operator-( const ConstTupleIterator& it1, const ConstTupleIterator& it2) noexcept { VTK_ITER_ASSERT(it1.GetArray() == it2.GetArray(), "Cannot do math with tuple iterators from different " "arrays."); return it1.GetTupleId() - it2.GetTupleId(); } friend VTK_ITER_INLINE void swap(ConstTupleIterator& lhs, ConstTupleIterator& rhs) noexcept { // Different arrays may use different iterator implementations. VTK_ITER_ASSERT( lhs.GetArray() == rhs.GetArray(), "Cannot swap iterators from different arrays."); using std::swap; swap(lhs.GetTupleId(), rhs.GetTupleId()); } private: VTK_ITER_INLINE ArrayType* GetArray() const noexcept { return this->Ref.Array; } VTK_ITER_INLINE ArrayType*& GetArray() noexcept { return this->Ref.Array; } VTK_ITER_INLINE NumCompsType GetNumComps() const noexcept { return this->Ref.NumComps; } VTK_ITER_INLINE NumCompsType& GetNumComps() noexcept { return this->Ref.NumComps; } VTK_ITER_INLINE TupleIdType GetTupleId() const noexcept { return this->Ref.TupleId; } VTK_ITER_INLINE TupleIdType& GetTupleId() noexcept { return this->Ref.TupleId; } ConstTupleReference Ref; }; //------------------------------------------------------------------------------ // Tuple iterator template struct TupleIterator { private: static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); using NumCompsType = GenericTupleSize; public: using iterator_category = std::random_access_iterator_tag; using value_type = TupleReference; using difference_type = TupleIdType; using pointer = TupleReference; using reference = TupleReference; VTK_ITER_INLINE TupleIterator() noexcept = default; VTK_ITER_INLINE TupleIterator(ArrayType* array, NumCompsType numComps, TupleIdType tupleId) noexcept : Ref(array, numComps, tupleId) { VTK_ITER_ASSERT(array != nullptr, "Invalid array."); VTK_ITER_ASSERT(numComps.value > 0, "Invalid number of components."); VTK_ITER_ASSERT( tupleId >= 0 && tupleId <= array->GetNumberOfTuples(), "Tuple iterator at invalid tuple id."); } VTK_ITER_INLINE TupleIterator(const TupleIterator& o) noexcept = default; VTK_ITER_INLINE TupleIterator& operator=(const TupleIterator& o) noexcept { this->Ref.CopyReference(o.Ref); return *this; } VTK_ITER_INLINE TupleIterator& operator++() noexcept // prefix { ++this->Ref.TupleId; VTK_ITER_ASSERT( this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(), "Tuple iterator at invalid component id."); return *this; } VTK_ITER_INLINE TupleIterator operator++(int) noexcept // postfix { return TupleIterator{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId++ }; } VTK_ITER_INLINE TupleIterator& operator--() noexcept // prefix { --this->Ref.TupleId; VTK_ITER_ASSERT( this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(), "Tuple iterator at invalid component id."); return *this; } VTK_ITER_INLINE TupleIterator operator--(int) noexcept // postfix { return TupleIterator{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId-- }; } VTK_ITER_INLINE reference operator[](difference_type i) noexcept { return reference{ this->Ref.Array, this->Ref.NumComps, this->Ref.TupleId + i }; } VTK_ITER_INLINE reference operator*() noexcept { return this->Ref; } VTK_ITER_INLINE pointer& operator->() noexcept { return this->Ref; } #define VTK_TMP_MAKE_OPERATOR(OP) \ friend VTK_ITER_INLINE bool operator OP( \ const TupleIterator& lhs, const TupleIterator& rhs) noexcept \ { \ VTK_ITER_ASSERT( \ lhs.GetArray() == rhs.GetArray(), "Cannot compare iterators from different arrays."); \ VTK_ITER_ASSUME(lhs.GetNumComps().value > 0); \ VTK_ITER_ASSUME(lhs.GetNumComps().value == rhs.GetNumComps().value); \ return lhs.GetTupleId() OP rhs.GetTupleId(); \ } VTK_TMP_MAKE_OPERATOR(==) VTK_TMP_MAKE_OPERATOR(!=) VTK_TMP_MAKE_OPERATOR(<) VTK_TMP_MAKE_OPERATOR(>) VTK_TMP_MAKE_OPERATOR(<=) VTK_TMP_MAKE_OPERATOR(>=) #undef VTK_TMP_MAKE_OPERATOR VTK_ITER_INLINE TupleIterator& operator+=(difference_type offset) noexcept { this->Ref.TupleId += offset; VTK_ITER_ASSERT( this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(), "Tuple iterator at invalid component id."); return *this; } friend VTK_ITER_INLINE TupleIterator operator+( const TupleIterator& it, difference_type offset) noexcept { return TupleIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId() + offset }; } friend VTK_ITER_INLINE TupleIterator operator+( difference_type offset, const TupleIterator& it) noexcept { return TupleIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId() + offset }; } VTK_ITER_INLINE TupleIterator& operator-=(difference_type offset) noexcept { this->Ref.TupleId -= offset; VTK_ITER_ASSERT( this->Ref.TupleId >= 0 && this->Ref.TupleId <= this->Ref.Array->GetNumberOfTuples(), "Tuple iterator at invalid component id."); return *this; } friend VTK_ITER_INLINE TupleIterator operator-( const TupleIterator& it, difference_type offset) noexcept { return TupleIterator{ it.GetArray(), it.GetNumComps(), it.GetTupleId() - offset }; } friend VTK_ITER_INLINE difference_type operator-( const TupleIterator& it1, const TupleIterator& it2) noexcept { VTK_ITER_ASSERT(it1.GetArray() == it2.GetArray(), "Cannot do math with tuple iterators from different " "arrays."); return it1.GetTupleId() - it2.GetTupleId(); } friend VTK_ITER_INLINE void swap(TupleIterator& lhs, TupleIterator& rhs) noexcept { // Different arrays may use different iterator implementations. VTK_ITER_ASSERT( lhs.GetArray() == rhs.GetArray(), "Cannot swap iterators from different arrays."); using std::swap; swap(lhs.GetTupleId(), rhs.GetTupleId()); } friend struct ConstTupleIterator; friend struct ConstTupleReference; protected: VTK_ITER_INLINE ArrayType* GetArray() const noexcept { return this->Ref.Array; } VTK_ITER_INLINE ArrayType*& GetArray() noexcept { return this->Ref.Array; } VTK_ITER_INLINE NumCompsType GetNumComps() const noexcept { return this->Ref.NumComps; } VTK_ITER_INLINE NumCompsType& GetNumComps() noexcept { return this->Ref.NumComps; } VTK_ITER_INLINE TupleIdType GetTupleId() const noexcept { return this->Ref.TupleId; } VTK_ITER_INLINE TupleIdType& GetTupleId() noexcept { return this->Ref.TupleId; } TupleReference Ref; }; //------------------------------------------------------------------------------ // Tuple range template struct TupleRange { private: using NumCompsType = GenericTupleSize; static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); public: using ArrayType = ArrayTypeT; using APIType = GetAPIType; using TupleIteratorType = TupleIterator; using ConstTupleIteratorType = ConstTupleIterator; using TupleReferenceType = TupleReference; using ConstTupleReferenceType = ConstTupleReference; using ComponentIteratorType = ComponentIterator; using ConstComponentIteratorType = ConstComponentIterator; using ComponentReferenceType = ComponentReference; using ConstComponentReferenceType = ConstComponentReference; using ComponentType = APIType; // May be DynamicTupleSize, or the actual tuple size. constexpr static ComponentIdType TupleSizeTag = TupleSize; using size_type = TupleIdType; using iterator = TupleIteratorType; using const_iterator = ConstTupleIteratorType; using reference = TupleReferenceType; using const_reference = ConstTupleReferenceType; VTK_ITER_INLINE TupleRange() noexcept = default; VTK_ITER_INLINE TupleRange(ArrayType* arr, TupleIdType beginTuple, TupleIdType endTuple) noexcept : Array(arr) , NumComps(arr) , BeginTuple(beginTuple) , EndTuple(endTuple) { assert(this->Array); assert(beginTuple >= 0 && beginTuple <= endTuple); assert(endTuple >= 0 && endTuple <= this->Array->GetNumberOfTuples()); } VTK_ITER_INLINE TupleRange GetSubRange(TupleIdType beginTuple = 0, TupleIdType endTuple = -1) const noexcept { const TupleIdType realBegin = this->BeginTuple + beginTuple; const TupleIdType realEnd = endTuple >= 0 ? this->BeginTuple + endTuple : this->EndTuple; return TupleRange{ this->Array, realBegin, realEnd }; } VTK_ITER_INLINE ArrayType* GetArray() const noexcept { return this->Array; } VTK_ITER_INLINE ComponentIdType GetTupleSize() const noexcept { return this->NumComps.value; } VTK_ITER_INLINE TupleIdType GetBeginTupleId() const noexcept { return this->BeginTuple; } VTK_ITER_INLINE TupleIdType GetEndTupleId() const noexcept { return this->EndTuple; } VTK_ITER_INLINE size_type size() const noexcept { return this->EndTuple - this->BeginTuple; } VTK_ITER_INLINE iterator begin() noexcept { return this->NewIter(this->BeginTuple); } VTK_ITER_INLINE iterator end() noexcept { return this->NewIter(this->EndTuple); } VTK_ITER_INLINE const_iterator begin() const noexcept { return this->NewCIter(this->BeginTuple); } VTK_ITER_INLINE const_iterator end() const noexcept { return this->NewCIter(this->EndTuple); } VTK_ITER_INLINE const_iterator cbegin() const noexcept { return this->NewCIter(this->BeginTuple); } VTK_ITER_INLINE const_iterator cend() const noexcept { return this->NewCIter(this->EndTuple); } VTK_ITER_INLINE reference operator[](size_type i) noexcept { return reference{ this->Array, this->NumComps, this->BeginTuple + i }; } VTK_ITER_INLINE const_reference operator[](size_type i) const noexcept { return const_reference{ this->Array, this->NumComps, this->BeginTuple + i }; } private: VTK_ITER_INLINE iterator NewIter(TupleIdType t) const { return iterator{ this->Array, this->NumComps, t }; } VTK_ITER_INLINE const_iterator NewCIter(TupleIdType t) const { return const_iterator{ this->Array, this->NumComps, t }; } mutable ArrayType* Array{ nullptr }; NumCompsType NumComps{}; TupleIdType BeginTuple{ 0 }; TupleIdType EndTuple{ 0 }; }; // Unimplemented, only used inside decltype in SelectTupleRange: template TupleRange DeclareTupleRangeSpecialization(vtkDataArray*); } // end namespace detail } // end namespace vtk VTK_ITER_OPTIMIZE_END #endif // __VTK_WRAP__ // VTK-HeaderTest-Exclude: vtkDataArrayTupleRange_Generic.h