vtk-m/vtkm/VecFromPortal.h
Kenneth Moreland 508cc3accb Improve = operators in VecFromPortal
Previously, `VecFromPortal` could only be set to a standard `Vec`.
However, because this is a `Vec`-like object with a runtime-size, it is
hard to do general arithmetic on it. It is easier to do in place so
there is some place to put the result. To make it easier to operate on
this as the result of other `Vec`-likes, extend the operators like `+=`,
`*=`, etc to support this.
2023-08-08 21:43:01 -04:00

249 lines
7.6 KiB
C++

//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt 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.
//============================================================================
#ifndef vtk_m_VecFromPortal_h
#define vtk_m_VecFromPortal_h
#include <vtkm/Math.h>
#include <vtkm/TypeTraits.h>
#include <vtkm/Types.h>
#include <vtkm/VecTraits.h>
#include <vtkm/internal/ArrayPortalValueReference.h>
namespace vtkm
{
/// \brief A short variable-length array from a window in an ArrayPortal.
///
/// The \c VecFromPortal class is a Vec-like class that holds an array portal
/// and exposes a small window of that portal as if it were a \c Vec.
///
template <typename PortalType>
class VecFromPortal
{
public:
using ComponentType = typename std::remove_const<typename PortalType::ValueType>::type;
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
VecFromPortal(const PortalType& portal, vtkm::IdComponent numComponents = 0, vtkm::Id offset = 0)
: Portal(portal)
, NumComponents(numComponents)
, Offset(offset)
{
}
VTKM_EXEC_CONT
vtkm::IdComponent GetNumberOfComponents() const { return this->NumComponents; }
template <typename T, vtkm::IdComponent DestSize>
VTKM_EXEC_CONT void CopyInto(vtkm::Vec<T, DestSize>& dest) const
{
vtkm::IdComponent numComponents = vtkm::Min(DestSize, this->NumComponents);
for (vtkm::IdComponent index = 0; index < numComponents; index++)
{
dest[index] = this->Portal.Get(index + this->Offset);
}
}
template <vtkm::IdComponent N>
VTKM_EXEC_CONT operator vtkm::Vec<ComponentType, N>() const
{
vtkm::Vec<ComponentType, N> result;
this->CopyInto(result);
for (vtkm::IdComponent index = this->NumComponents; index < N; ++index)
{
result[index] = vtkm::TypeTraits<ComponentType>::ZeroInitialization();
}
return result;
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
vtkm::internal::ArrayPortalValueReference<PortalType> operator[](vtkm::IdComponent index) const
{
return vtkm::internal::ArrayPortalValueReference<PortalType>(this->Portal,
index + this->Offset);
}
// Only works with Vec-like objects with operator[] and GetNumberofComponents
template <typename OtherVecType>
VTKM_EXEC_CONT VecFromPortal& operator=(const OtherVecType& src)
{
vtkm::IdComponent numComponents = vtkm::Min(src.GetNumberOfComponents(), this->NumComponents);
for (vtkm::IdComponent index = 0; index < numComponents; ++index)
{
this->Portal.Set(index + this->Offset, src[index]);
}
return *this;
}
// Only works with Vec-like objects with operator[] and GetNumberofComponents
template <typename OtherVecType>
VTKM_EXEC_CONT VecFromPortal& operator+=(const OtherVecType& other)
{
vtkm::IdComponent numComponents = vtkm::Min(other.GetNumberOfComponents(), this->NumComponents);
for (vtkm::IdComponent index = 0; index < numComponents; ++index)
{
(*this)[index] += other[index];
}
return *this;
}
// Only works with Vec-like objects with operator[] and GetNumberofComponents
template <typename OtherVecType>
VTKM_EXEC_CONT VecFromPortal& operator-=(const OtherVecType& other)
{
vtkm::IdComponent numComponents = vtkm::Min(other.GetNumberOfComponents(), this->NumComponents);
for (vtkm::IdComponent index = 0; index < numComponents; ++index)
{
(*this)[index] -= other[index];
}
return *this;
}
private:
template <typename OtherVecType>
VTKM_EXEC_CONT void Multiply(const OtherVecType& other, vtkm::TypeTraitsVectorTag)
{
vtkm::IdComponent numComponents = vtkm::Min(other.GetNumberOfComponents(), this->NumComponents);
for (vtkm::IdComponent index = 0; index < numComponents; ++index)
{
(*this)[index] *= other[index];
}
}
template <typename ScalarType>
VTKM_EXEC_CONT void Multiply(ScalarType other, vtkm::TypeTraitsScalarTag)
{
for (vtkm::IdComponent index = 0; index < this->NumComponents; ++index)
{
(*this)[index] *= other;
}
}
public:
// Only works with Vec-like objects with operator[] and GetNumberofComponents
template <typename OtherVecType>
VTKM_EXEC_CONT VecFromPortal& operator*=(const OtherVecType& other)
{
this->Multiply(other, typename vtkm::TypeTraits<OtherVecType>::DimensionalityTag{});
return *this;
}
// Only works with Vec-like objects with operator[] and GetNumberofComponents
template <typename OtherVecType>
VTKM_EXEC_CONT VecFromPortal& operator/=(const OtherVecType& other)
{
vtkm::IdComponent numComponents = vtkm::Min(other.GetNumberOfComponents(), this->NumComponents);
for (vtkm::IdComponent index = 0; index < numComponents; ++index)
{
(*this)[index] /= other[index];
}
return *this;
}
// Only works with Vec-like objects with operator[] and GetNumberofComponents
template <typename OtherVecType>
VTKM_EXEC_CONT bool operator==(const OtherVecType& other)
{
if (this->NumComponents != other.GetNumberOfComponents())
{
return false;
}
for (vtkm::IdComponent index = 0; index < this->NumComponents; ++index)
{
if (this->Portal.Get(index + this->Offset) != other[index])
{
return false;
}
}
return true;
}
// Only works with Vec-like objects with operator[] and GetNumberofComponents
template <typename OtherVecType>
VTKM_EXEC_CONT bool operator!=(const OtherVecType& other)
{
return !(*this == other);
}
VTKM_EXEC_CONT const PortalType& GetPortal() const { return this->Portal; }
VTKM_EXEC_CONT vtkm::Id GetOffset() const { return this->Offset; }
private:
PortalType Portal;
vtkm::IdComponent NumComponents;
vtkm::Id Offset;
};
template <typename PortalType>
struct TypeTraits<vtkm::VecFromPortal<PortalType>>
{
private:
using ComponentType = typename PortalType::ValueType;
public:
using NumericTag = typename vtkm::TypeTraits<ComponentType>::NumericTag;
using DimensionalityTag = TypeTraitsVectorTag;
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
static vtkm::VecFromPortal<PortalType> ZeroInitialization()
{
return vtkm::VecFromPortal<PortalType>();
}
};
template <typename PortalType>
struct VecTraits<vtkm::VecFromPortal<PortalType>>
{
using VecType = vtkm::VecFromPortal<PortalType>;
using ComponentType = typename VecType::ComponentType;
using BaseComponentType = typename vtkm::VecTraits<ComponentType>::BaseComponentType;
using HasMultipleComponents = vtkm::VecTraitsTagMultipleComponents;
using IsSizeStatic = vtkm::VecTraitsTagSizeVariable;
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
static vtkm::IdComponent GetNumberOfComponents(const VecType& vector)
{
return vector.GetNumberOfComponents();
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
static ComponentType GetComponent(const VecType& vector, vtkm::IdComponent componentIndex)
{
return vector[componentIndex];
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
static void SetComponent(const VecType& vector,
vtkm::IdComponent componentIndex,
const ComponentType& value)
{
vector[componentIndex] = value;
}
VTKM_SUPPRESS_EXEC_WARNINGS
template <vtkm::IdComponent destSize>
VTKM_EXEC_CONT static void CopyInto(const VecType& src, vtkm::Vec<ComponentType, destSize>& dest)
{
src.CopyInto(dest);
}
};
} // namespace vtkm
#endif //vtk_m_VecFromPortal_h