You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
972 lines
30 KiB
C++
972 lines
30 KiB
C++
/*=========================================================================
|
|
|
|
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 <algorithm>
|
|
#include <cassert>
|
|
#include <iterator>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
|
|
#ifndef __VTK_WRAP__
|
|
|
|
VTK_ITER_OPTIMIZE_START
|
|
|
|
namespace vtk
|
|
{
|
|
|
|
namespace detail
|
|
{
|
|
|
|
// Forward decs for friends/args
|
|
template <typename ArrayType, ComponentIdType>
|
|
struct ValueReference;
|
|
template <typename ArrayType, ComponentIdType>
|
|
struct ConstValueReference;
|
|
template <typename ArrayType, ComponentIdType>
|
|
struct ValueIterator;
|
|
template <typename ArrayType, ComponentIdType>
|
|
struct ConstValueIterator;
|
|
template <typename ArrayType, ComponentIdType>
|
|
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 <ComponentIdType TupleSize>
|
|
struct IdStorage
|
|
{
|
|
using NumCompsType = GenericTupleSize<TupleSize>;
|
|
|
|
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<TupleIdType>(valueId) / static_cast<TupleIdType>(numComps.value))
|
|
, ComponentId(static_cast<ComponentIdType>(valueId % static_cast<ValueIdType>(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 <typename ArrayType>
|
|
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<ValueIdType>(tuple) * this->NumComps.value + comp;
|
|
}
|
|
|
|
VTK_ITER_INLINE
|
|
std::pair<TupleIdType, ComponentIdType> Convert(ValueIdType value) const noexcept
|
|
{
|
|
return std::make_pair(static_cast<TupleIdType>(value / this->NumComps.value),
|
|
static_cast<ComponentIdType>(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 <typename ArrayType, ComponentIdType TupleSize>
|
|
struct ConstValueReference
|
|
{
|
|
private:
|
|
static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
|
|
static_assert(IsVtkDataArray<ArrayType>::value, "Invalid array type.");
|
|
|
|
using IdStorageType = IdStorage<TupleSize>;
|
|
using APIType = GetAPIType<ArrayType>;
|
|
|
|
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<ArrayType, TupleSize>& 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<ArrayType> acc{ this->Array };
|
|
return acc.Get(this->Id.GetTupleId(), this->Id.GetComponentId());
|
|
}
|
|
|
|
protected:
|
|
mutable ArrayType* Array;
|
|
IdStorageType Id;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Value reference
|
|
template <typename ArrayType, ComponentIdType TupleSize>
|
|
struct ValueReference
|
|
{
|
|
private:
|
|
static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
|
|
static_assert(IsVtkDataArray<ArrayType>::value, "Invalid array type.");
|
|
|
|
using APIType = GetAPIType<ArrayType>;
|
|
using IdStorageType = IdStorage<TupleSize>;
|
|
|
|
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<APIType>(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<APIType>(o);
|
|
}
|
|
else
|
|
{ // Initialize the reference:
|
|
this->Array = std::move(o.Array);
|
|
this->Id = std::move(o.Id);
|
|
return *this;
|
|
}
|
|
}
|
|
|
|
template <typename OArray, ComponentIdType OSize>
|
|
VTK_ITER_INLINE ValueReference operator=(const ValueReference<OArray, OSize>& 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<ArrayType> 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<ArrayType> 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<APIType>(lhs));
|
|
lhs = std::move(static_cast<APIType>(rhs));
|
|
rhs = std::move(tmp);
|
|
}
|
|
|
|
template <typename OArray, ComponentIdType OSize>
|
|
friend VTK_ITER_INLINE void swap(ValueReference lhs, ValueReference<OArray, OSize> rhs) noexcept
|
|
{ // Swap values, not references:
|
|
using OAPIType = typename ValueReference<OArray, OSize>::value_type;
|
|
static_assert(
|
|
std::is_same<APIType, OAPIType>::value, "Cannot swap components with different types.");
|
|
|
|
APIType tmp = std::move(static_cast<APIType>(lhs));
|
|
lhs = std::move(static_cast<APIType>(rhs));
|
|
rhs = std::move(tmp);
|
|
}
|
|
|
|
friend VTK_ITER_INLINE void swap(ValueReference lhs, APIType& rhs) noexcept
|
|
{
|
|
APIType tmp = std::move(static_cast<APIType>(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<APIType>(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<ArrayType, TupleSize>;
|
|
friend struct ValueIterator<ArrayType, TupleSize>;
|
|
|
|
protected:
|
|
void CopyReference(const ValueReference& o) noexcept
|
|
{
|
|
this->Array = o.Array;
|
|
this->Id = o.Id;
|
|
}
|
|
|
|
mutable ArrayType* Array;
|
|
IdStorageType Id;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Const value iterator
|
|
template <typename ArrayType, ComponentIdType TupleSize>
|
|
struct ConstValueIterator
|
|
: public std::iterator<std::random_access_iterator_tag, GetAPIType<ArrayType>, ValueIdType,
|
|
// expected types don't have members, no op->().
|
|
void, ConstValueReference<ArrayType, TupleSize> >
|
|
{
|
|
private:
|
|
static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
|
|
static_assert(IsVtkDataArray<ArrayType>::value, "Invalid array type.");
|
|
|
|
using APIType = GetAPIType<ArrayType>;
|
|
using IdStorageType = IdStorage<TupleSize>;
|
|
using Superclass = std::iterator<std::random_access_iterator_tag, APIType, ValueIdType, void,
|
|
ConstValueReference<ArrayType, TupleSize> >;
|
|
|
|
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<ArrayType, TupleSize>& 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 <typename ArrayType, ComponentIdType TupleSize>
|
|
struct ValueIterator
|
|
: public std::iterator<std::random_access_iterator_tag, vtk::GetAPIType<ArrayType>, ValueIdType,
|
|
ValueReference<ArrayType, TupleSize>, ValueReference<ArrayType, TupleSize> >
|
|
{
|
|
private:
|
|
static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
|
|
static_assert(IsVtkDataArray<ArrayType>::value, "Invalid array type.");
|
|
|
|
using APIType = GetAPIType<ArrayType>;
|
|
using IdStorageType = IdStorage<TupleSize>;
|
|
using Superclass = std::iterator<std::random_access_iterator_tag, GetAPIType<ArrayType>,
|
|
ValueIdType, ValueReference<ArrayType, TupleSize>, ValueReference<ArrayType, TupleSize> >;
|
|
|
|
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<ArrayType, TupleSize>;
|
|
|
|
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<ArrayType, TupleSize> Ref;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// ValueRange
|
|
template <typename ArrayTypeT, ComponentIdType TupleSize>
|
|
struct ValueRange
|
|
{
|
|
private:
|
|
static_assert(IsValidTupleSize<TupleSize>::value, "Invalid tuple size.");
|
|
static_assert(IsVtkDataArray<ArrayTypeT>::value, "Invalid array type.");
|
|
|
|
using IdStorageType = IdStorage<TupleSize>;
|
|
using NumCompsType = GenericTupleSize<TupleSize>;
|
|
|
|
public:
|
|
using ArrayType = ArrayTypeT;
|
|
using ValueType = GetAPIType<ArrayTypeT>;
|
|
|
|
using IteratorType = ValueIterator<ArrayType, TupleSize>;
|
|
using ConstIteratorType = ConstValueIterator<ArrayType, TupleSize>;
|
|
using ReferenceType = ValueReference<ArrayType, TupleSize>;
|
|
using ConstReferenceType = ConstValueReference<ArrayType, TupleSize>;
|
|
|
|
// 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 <typename ArrayType, ComponentIdType TupleSize>
|
|
ValueRange<ArrayType, TupleSize> 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
|