/*========================================================================= Program: Visualization Toolkit Module: vtkDataArrayValueRange_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 vtkDataArrayValueRange_Generic_h #define vtkDataArrayValueRange_Generic_h #include "vtkDataArrayAccessor.h" #include "vtkDataArrayMeta.h" #include #include #include #include #include #ifndef __VTK_WRAP__ VTK_ITER_OPTIMIZE_START namespace vtk { namespace detail { // Forward decs for friends/args template struct ValueReference; template struct ConstValueReference; template struct ValueIterator; template struct ConstValueIterator; template struct ValueRange; //------------------------------------------------------------------------------ // Helper that converts ValueId <--> { TupleId, ComponentId } // This class stores both representations. Profiling and assembly inspection // show that ValueId is much more efficient for comparing Ids, while Tuple/Comp // ids are much faster for looking up elements (especially when considering // SOA arrays). The overhead of maintaining both is low, and this class is // transparent enough that the compiler will produce efficient ASM with // simple optimizations enabled. template struct IdStorage { using NumCompsType = GenericTupleSize; VTK_ITER_INLINE IdStorage() noexcept : ValueId(0) , TupleId(0) , ComponentId(0) { } VTK_ITER_INLINE IdStorage(ValueIdType valueId, NumCompsType numComps) noexcept : ValueId(valueId) , TupleId(static_cast(valueId) / static_cast(numComps.value)) , ComponentId(static_cast(valueId % static_cast(numComps.value))) , NumComps(numComps) { } VTK_ITER_INLINE IdStorage(TupleIdType tupleId, ComponentIdType comp, NumCompsType numComps) noexcept : ValueId(tupleId* numComps.value + comp) , TupleId(tupleId) , ComponentId(comp) , NumComps(numComps) { } VTK_ITER_INLINE IdStorage( ValueIdType valueId, TupleIdType tupleId, ComponentIdType comp, NumCompsType numComps) noexcept : ValueId(valueId) , TupleId(tupleId) , ComponentId(comp) , NumComps(numComps) { } template VTK_ITER_INLINE void DebugAsserts(ArrayType* array) const noexcept { (void)array; VTK_ITER_ASSERT(array != nullptr, "Invalid array."); VTK_ITER_ASSERT(this->ValueId == this->TupleId * this->GetTupleSize() + this->ComponentId, "Inconsistent internal state in IdStorage."); VTK_ITER_ASSERT(this->GetTupleSize() > 0, "Invalid number of components."); VTK_ITER_ASSERT( this->ValueId >= 0 && this->ValueId <= array->GetNumberOfValues(), "Invalid value id."); VTK_ITER_ASSERT(this->GetTupleId() >= 0 && this->GetTupleId() <= array->GetNumberOfTuples(), "Invalid tuple id."); VTK_ITER_ASSERT(this->GetComponentId() >= 0 && (this->GetComponentId() < this->GetTupleSize() || (this->GetComponentId() == this->GetTupleSize() && this->GetTupleId() == array->GetNumberOfTuples())), "Invalid component id."); VTK_ITER_ASSERT(this->GetValueId() >= 0 && this->GetValueId() <= array->GetNumberOfValues(), "Invalid value id."); } VTK_ITER_INLINE IdStorage& operator++() noexcept // prefix { ++this->ValueId; ++this->ComponentId; if (this->ComponentId == this->GetTupleSize()) { this->ComponentId = 0; ++this->TupleId; } return *this; } VTK_ITER_INLINE IdStorage operator++(int) noexcept // postfix { auto v = this->ValueId++; auto t = this->TupleId; auto c = this->ComponentId++; if (this->ComponentId == this->GetTupleSize()) { this->ComponentId = 0; ++this->TupleId; } return IdStorage{ v, t, c, this->NumComps }; } friend VTK_ITER_INLINE IdStorage operator+(const IdStorage& id, ValueIdType offset) noexcept { IdStorage res = id; res.AddOffset(offset); return res; } VTK_ITER_INLINE IdStorage& operator--() noexcept // prefix { --this->ValueId; --this->ComponentId; if (this->ComponentId < 0) { this->ComponentId = this->GetTupleSize() - 1; --this->TupleId; } return *this; } VTK_ITER_INLINE IdStorage operator--(int) noexcept // postfix { auto v = this->ValueId--; auto t = this->TupleId; auto c = this->ComponentId--; if (this->ComponentId < 0) { this->ComponentId = this->GetTupleSize() - 1; --this->TupleId; } return IdStorage{ v, t, c, this->NumComps }; } VTK_ITER_INLINE ValueIdType Convert(TupleIdType tuple, ComponentIdType comp) const noexcept { return static_cast(tuple) * this->NumComps.value + comp; } VTK_ITER_INLINE std::pair Convert(ValueIdType value) const noexcept { return std::make_pair(static_cast(value / this->NumComps.value), static_cast(value % this->NumComps.value)); } VTK_ITER_INLINE void AddOffset(ValueIdType offset) noexcept { this->ValueId += offset; std::tie(this->TupleId, this->ComponentId) = this->Convert(this->ValueId); } VTK_ITER_INLINE ComponentIdType GetTupleSize() const noexcept { return this->NumComps.value; } VTK_ITER_INLINE TupleIdType GetTupleId() const noexcept { return this->TupleId; } VTK_ITER_INLINE ComponentIdType GetComponentId() const noexcept { return this->ComponentId; } VTK_ITER_INLINE ValueIdType GetValueId() const noexcept { return this->ValueId; } friend VTK_ITER_INLINE void swap(IdStorage& lhs, IdStorage& rhs) noexcept { using std::swap; swap(lhs.ValueId, rhs.ValueId); swap(lhs.TupleId, rhs.TupleId); swap(lhs.ComponentId, rhs.ComponentId); } private: vtk::ValueIdType ValueId; vtk::TupleIdType TupleId; vtk::ComponentIdType ComponentId; NumCompsType NumComps; }; //------------------------------------------------------------------------------ // Value reference template struct ConstValueReference { private: static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); using IdStorageType = IdStorage; using APIType = GetAPIType; public: VTK_ITER_INLINE ConstValueReference() noexcept : Array{ nullptr } , Id{} { } VTK_ITER_INLINE ConstValueReference(ArrayType* array, IdStorageType id) noexcept : Array{ array } , Id{ id } { this->Id.DebugAsserts(array); } VTK_ITER_INLINE ConstValueReference(const ValueReference& o) : Array{ o.Array } , Id{ o.Id } { } VTK_ITER_INLINE ConstValueReference(const ConstValueReference& o) noexcept = default; VTK_ITER_INLINE ConstValueReference(ConstValueReference&& o) noexcept = default; VTK_ITER_INLINE ConstValueReference operator=(const ConstValueReference& o) noexcept { VTK_ITER_ASSERT(!this->Array, "Const reference already initialized."); // Initialize the reference. this->Array = o.Array; this->Id = o.Id; return *this; } VTK_ITER_INLINE ConstValueReference operator=(ConstValueReference&& o) noexcept { VTK_ITER_ASSERT(!this->Array, "Const reference already initialized."); // Initialize the reference. this->Array = std::move(o.Array); this->Id = std::move(o.Id); return *this; } VTK_ITER_INLINE operator APIType() const noexcept { VTK_ITER_ASSUME(this->Id.GetTupleSize() > 0); VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->Id.GetTupleSize()); vtkDataArrayAccessor acc{ this->Array }; return acc.Get(this->Id.GetTupleId(), this->Id.GetComponentId()); } protected: mutable ArrayType* Array; IdStorageType Id; }; //------------------------------------------------------------------------------ // Value reference template struct ValueReference { private: static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); using APIType = GetAPIType; using IdStorageType = IdStorage; public: using value_type = APIType; VTK_ITER_INLINE ValueReference() noexcept : Array{ nullptr } , Id{} { } VTK_ITER_INLINE ValueReference(ArrayType* array, IdStorageType id) noexcept : Array{ array } , Id{ id } { this->Id.DebugAsserts(this->Array); } VTK_ITER_INLINE ValueReference(const ValueReference& o) noexcept = default; VTK_ITER_INLINE ValueReference(ValueReference&& o) noexcept = default; VTK_ITER_INLINE ValueReference operator=(const ValueReference& 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->Id = o.Id; return *this; } } VTK_ITER_INLINE ValueReference operator=(ValueReference&& o) noexcept { if (this->Array) { // Already initialized. Assign the value, not the reference: return *this = static_cast(o); } else { // Initialize the reference: this->Array = std::move(o.Array); this->Id = std::move(o.Id); return *this; } } template VTK_ITER_INLINE ValueReference operator=(const ValueReference& 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->Id.GetTupleSize() > 0); VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->Id.GetTupleSize()); vtkDataArrayAccessor acc{ this->Array }; return acc.Get(this->Id.GetTupleId(), this->Id.GetComponentId()); } VTK_ITER_INLINE ValueReference operator=(APIType val) noexcept { VTK_ITER_ASSUME(this->Id.GetTupleSize() > 0); VTK_ITER_ASSUME(this->Array->GetNumberOfComponents() == this->Id.GetTupleSize()); vtkDataArrayAccessor acc{ this->Array }; acc.Set(this->Id.GetTupleId(), this->Id.GetComponentId(), val); return *this; } friend VTK_ITER_INLINE void swap(ValueReference lhs, ValueReference 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(ValueReference lhs, ValueReference rhs) noexcept { // Swap values, not references: using OAPIType = typename ValueReference::value_type; 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(ValueReference 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, ValueReference rhs) noexcept { APIType tmp = std::move(lhs); lhs = std::move(static_cast(rhs)); rhs = std::move(tmp); } VTK_ITER_INLINE ValueReference 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 ValueReference 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 ValueReference operator Op(ValueReference lhs, APIType val) noexcept \ { \ const APIType newVal = lhs ImplOp val; \ lhs = newVal; \ return lhs; \ } \ friend VTK_ITER_INLINE ValueReference operator Op(ValueReference lhs, ValueReference val) \ noexcept \ { \ const APIType newVal = lhs ImplOp val; \ lhs = newVal; \ return lhs; \ } \ friend VTK_ITER_INLINE APIType& operator Op(APIType& lhs, ValueReference 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 ConstValueReference; friend struct ValueIterator; protected: void CopyReference(const ValueReference& o) noexcept { this->Array = o.Array; this->Id = o.Id; } mutable ArrayType* Array; IdStorageType Id; }; //------------------------------------------------------------------------------ // Const value iterator template struct ConstValueIterator : public std::iterator, ValueIdType, // expected types don't have members, no op->(). void, ConstValueReference > { private: static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); using APIType = GetAPIType; using IdStorageType = IdStorage; using Superclass = std::iterator >; public: using iterator_category = typename Superclass::iterator_category; using value_type = typename Superclass::value_type; using difference_type = typename Superclass::difference_type; using pointer = typename Superclass::pointer; using reference = typename Superclass::reference; VTK_ITER_INLINE ConstValueIterator() noexcept : Array(nullptr) , Id() { } VTK_ITER_INLINE ConstValueIterator(ArrayType* array, IdStorageType id) noexcept : Array(array) , Id(id) { this->Id.DebugAsserts(this->Array); } VTK_ITER_INLINE ConstValueIterator(const ValueIterator& o) noexcept : Array{ o.GetArray() } , Id{ o.GetId() } { } VTK_ITER_INLINE ConstValueIterator(const ConstValueIterator& o) noexcept = default; VTK_ITER_INLINE ConstValueIterator& operator=(const ConstValueIterator& o) noexcept = default; VTK_ITER_INLINE ConstValueIterator& operator++() noexcept // prefix { ++this->Id; this->Id.DebugAsserts(this->Array); return *this; } VTK_ITER_INLINE ConstValueIterator operator++(int) noexcept // postfix { auto ret = this->Id++; this->Id.DebugAsserts(this->Array); return ConstValueIterator{ this->Array, ret }; } VTK_ITER_INLINE ConstValueIterator& operator--() noexcept // prefix { --this->Id; this->Id.DebugAsserts(this->Array); return *this; } VTK_ITER_INLINE ConstValueIterator operator--(int) noexcept // postfix { auto ret = this->Id--; this->Id.DebugAsserts(this->Array); return ConstValueIterator{ this->Array, ret }; } VTK_ITER_INLINE reference operator[](difference_type i) const noexcept { return reference{ this->Array, this->Id + i }; } VTK_ITER_INLINE reference operator*() const noexcept { return reference{ this->Array, this->Id }; } // Using GetValueType here makes iteration 50% faster by reducing comparisons // and jumps (instead of comparing std::tie(tupleId, compId)). #define VTK_TMP_MAKE_OPERATOR(OP) \ friend VTK_ITER_INLINE bool operator OP( \ const ConstValueIterator& lhs, const ConstValueIterator& rhs) noexcept \ { \ VTK_ITER_ASSERT(lhs.Array == rhs.Array, "Mismatched arrays in iterator comparison."); \ return lhs.Id.GetValueId() OP rhs.Id.GetValueId(); \ } 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 ConstValueIterator& operator+=(difference_type offset) noexcept { this->Id.AddOffset(offset); this->Id.DebugAsserts(this->Array); return *this; } friend VTK_ITER_INLINE ConstValueIterator operator+( const ConstValueIterator& it, difference_type offset) noexcept { return ConstValueIterator{ it.Array, it.Id + offset }; } friend VTK_ITER_INLINE ConstValueIterator operator+( difference_type offset, const ConstValueIterator& it) noexcept { return ConstValueIterator{ it.Array, it.Id + offset }; } VTK_ITER_INLINE ConstValueIterator& operator-=(difference_type offset) noexcept { this->Id.AddOffset(-offset); this->Id.DebugAsserts(this->Array); return *this; } friend VTK_ITER_INLINE ConstValueIterator operator-( const ConstValueIterator& it, difference_type offset) noexcept { return ConstValueIterator{ it.Array, it.Id + (-offset) }; } friend VTK_ITER_INLINE difference_type operator-( const ConstValueIterator& it1, const ConstValueIterator& it2) noexcept { VTK_ITER_ASSERT(it1.Array == it2.Array, "Cannot do math with iterators from different arrays."); return it1.Id.GetValueId() - it2.Id.GetValueId(); } friend VTK_ITER_INLINE void swap(ConstValueIterator& lhs, ConstValueIterator& 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.Id, rhs.Id); } private: mutable ArrayType* Array; IdStorageType Id; }; //------------------------------------------------------------------------------ // Component iterator template struct ValueIterator : public std::iterator, ValueIdType, ValueReference, ValueReference > { private: static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); using APIType = GetAPIType; using IdStorageType = IdStorage; using Superclass = std::iterator, ValueIdType, ValueReference, ValueReference >; public: using iterator_category = typename Superclass::iterator_category; using value_type = typename Superclass::value_type; using difference_type = typename Superclass::difference_type; using pointer = typename Superclass::pointer; using reference = typename Superclass::reference; VTK_ITER_INLINE ValueIterator() noexcept = default; VTK_ITER_INLINE ValueIterator(ArrayType* array, IdStorageType id) noexcept : Ref{ array, id } { this->DebugIdAsserts(); } VTK_ITER_INLINE ValueIterator(const ValueIterator& o) noexcept = default; VTK_ITER_INLINE ValueIterator& operator=(const ValueIterator& o) noexcept { this->Ref.CopyReference(o.Ref); this->DebugIdAsserts(); return *this; } VTK_ITER_INLINE ValueIterator& operator++() noexcept // prefix { ++this->Ref.Id; this->DebugIdAsserts(); return *this; } VTK_ITER_INLINE ValueIterator operator++(int) noexcept // postfix { auto ret = this->Ref.Id++; this->DebugIdAsserts(); return ValueIterator{ this->Ref.Array, ret }; } VTK_ITER_INLINE ValueIterator& operator--() noexcept // prefix { --this->Ref.Id; this->DebugIdAsserts(); return *this; } VTK_ITER_INLINE ValueIterator operator--(int) noexcept // postfix { auto ret = this->Ref.Id--; this->DebugIdAsserts(); return ValueIterator{ this->Ref.Array, ret }; } VTK_ITER_INLINE reference operator[](difference_type i) const noexcept { return reference{ this->Ref.Array, this->Ref.Id + 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 ValueIterator& lhs, const ValueIterator& rhs) \ noexcept \ { \ VTK_ITER_ASSERT( \ lhs.GetArray() == rhs.GetArray(), "Mismatched arrays in iterator comparison."); \ return lhs.GetId().GetValueId() OP rhs.GetId().GetValueId(); \ } 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 ValueIterator& operator+=(difference_type offset) noexcept { this->Ref.Id.AddOffset(offset); this->DebugIdAsserts(); return *this; } friend VTK_ITER_INLINE ValueIterator operator+( const ValueIterator& it, difference_type offset) noexcept { return ValueIterator{ it.GetArray(), it.GetId() + offset }; } friend VTK_ITER_INLINE ValueIterator operator+( difference_type offset, const ValueIterator& it) noexcept { return ValueIterator{ it.GetArray(), it.GetId() + offset }; } VTK_ITER_INLINE ValueIterator& operator-=(difference_type offset) noexcept { this->Ref.Id.AddOffset(-offset); this->Ref.Id.DebugAsserts(this->Ref.Array); return *this; } friend VTK_ITER_INLINE ValueIterator operator-( const ValueIterator& it, difference_type offset) noexcept { return ValueIterator{ it.GetArray(), it.GetId() + (-offset) }; } friend VTK_ITER_INLINE difference_type operator-( const ValueIterator& it1, const ValueIterator& it2) noexcept { VTK_ITER_ASSERT( it1.Ref.Array == it2.Ref.Array, "Cannot do math with iterators from different arrays."); return it1.GetId().GetValueId() - it2.GetId().GetValueId(); } friend VTK_ITER_INLINE void swap(ValueIterator& lhs, ValueIterator& 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.GetId(), rhs.GetId()); } friend struct ConstValueIterator; protected: VTK_ITER_INLINE void DebugIdAsserts() const { this->Ref.Id.DebugAsserts(this->Ref.Array); } // 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; } IdStorageType& GetId() noexcept { return this->Ref.Id; } const IdStorageType& GetId() const noexcept { return this->Ref.Id; } ValueReference Ref; }; //------------------------------------------------------------------------------ // ValueRange template struct ValueRange { private: static_assert(IsValidTupleSize::value, "Invalid tuple size."); static_assert(IsVtkDataArray::value, "Invalid array type."); using IdStorageType = IdStorage; using NumCompsType = GenericTupleSize; public: using ArrayType = ArrayTypeT; using ValueType = GetAPIType; using IteratorType = ValueIterator; using ConstIteratorType = ConstValueIterator; using ReferenceType = ValueReference; using ConstReferenceType = ConstValueReference; // May be DynamicTupleSize, or the actual tuple size. constexpr static ComponentIdType TupleSizeTag = TupleSize; // STL-compat using value_type = ValueType; using size_type = ValueIdType; using iterator = IteratorType; using const_iterator = ConstIteratorType; using reference = ReferenceType; using const_reference = ConstReferenceType; VTK_ITER_INLINE ValueRange() noexcept = default; VTK_ITER_INLINE ValueRange(ArrayType* arr, ValueIdType beginValue, ValueIdType endValue) noexcept : Array(arr) , NumComps(arr) , BeginValue(beginValue, this->NumComps) , EndValue(endValue, this->NumComps) { assert(this->Array); assert(beginValue >= 0 && beginValue <= endValue); assert(endValue >= 0 && endValue <= this->Array->GetNumberOfValues()); } VTK_ITER_INLINE ValueRange GetSubRange(ValueIdType beginValue = 0, ValueIdType endValue = -1) const noexcept { const ValueIdType realBegin = this->BeginValue.GetValueId() + beginValue; const ValueIdType realEnd = endValue >= 0 ? this->BeginValue.GetValueId() + endValue : this->EndValue.GetValueId(); return ValueRange{ 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 ValueIdType GetBeginValueId() const noexcept { return this->BeginValue.GetValueId(); } VTK_ITER_INLINE ValueIdType GetEndValueId() const noexcept { return this->EndValue.GetValueId(); } VTK_ITER_INLINE size_type size() const noexcept { return this->EndValue.GetValueId() - this->BeginValue.GetValueId(); } VTK_ITER_INLINE iterator begin() noexcept { return this->NewIterator(this->BeginValue); } VTK_ITER_INLINE iterator end() noexcept { return this->NewIterator(this->EndValue); } VTK_ITER_INLINE const_iterator begin() const noexcept { return this->NewConstIterator(this->BeginValue); } VTK_ITER_INLINE const_iterator end() const noexcept { return this->NewConstIterator(this->EndValue); } VTK_ITER_INLINE const_iterator cbegin() const noexcept { return this->NewConstIterator(this->BeginValue); } VTK_ITER_INLINE const_iterator cend() const noexcept { return this->NewConstIterator(this->EndValue); } VTK_ITER_INLINE reference operator[](size_type i) noexcept { return reference{ this->Array, this->BeginValue + i }; } VTK_ITER_INLINE const_reference operator[](size_type i) const noexcept { return const_reference{ this->Array, this->BeginValue + i }; } private: VTK_ITER_INLINE iterator NewIterator(IdStorageType id) const noexcept { return iterator{ this->Array, id }; } VTK_ITER_INLINE const_iterator NewConstIterator(IdStorageType id) const noexcept { return const_iterator{ this->Array, id }; } mutable ArrayType* Array{ nullptr }; NumCompsType NumComps{}; IdStorageType BeginValue{}; IdStorageType EndValue{}; }; // Unimplemented, only used inside decltype in SelectValueRange: template ValueRange DeclareValueRangeSpecialization(vtkDataArray*); } // end namespace detail } // end namespace vtk VTK_ITER_OPTIMIZE_END #endif // __VTK_WRAP__ #endif // vtkDataArrayValueRange_Generic_h // VTK-HeaderTest-Exclude: vtkDataArrayValueRange_Generic.h