Add recursive component queries to VecTraits

Added a BaseComponentType to VecTraits that recursively finds the base
(non-Vec) type of a Vec. This is useful when dealing with potentially
nested Vec's (e.g. Vec<Vec<T, M>, N>) and you need to keep the structure
but know the base type.

Also added a couple of templates for keeping the structure but changing
the type. These are ReplaceComponentType and ReplaceBaseComponentType.
These allow you to create new Vec's with the same structure as the query
Vec but with differen component types.
This commit is contained in:
Kenneth Moreland 2019-09-02 21:52:56 -06:00
parent dca71a60de
commit 6323d6803e
8 changed files with 227 additions and 4 deletions

@ -0,0 +1,34 @@
# Recursive base component queries to VecTraits
This change adds a recursive `BaseComponentType` to `VecTraits` that
recursively finds the base (non-`Vec`) type of a `Vec`. This is useful when
dealing with potentially nested `Vec`s (e.g. `Vec<Vec<T, M>, N>`) and you
want to know the precision of the math being defined.
``` cpp
using NestedVec = vtkm::Vec<vtkm::Vec<vtkm::Float32, 3>, 8>;
// ComponentType becomes vtkm::Vec<vtkm::Float32, 3>
using ComponentType = typename vtkm::VecTraits<NestedVec>::ComponentType;
// BaseComponentType becomes vtkm::Float32
using BaseComponentType = typename vtkm::VecTraits<NestedVec>::BaseComponentType;
```
Also added the ability to `VecTraits` to change the component type of a
vector. The template `RepalceComponentType` resolves to a `Vec` of the same
type with the component replaced with a new type. The template
`ReplaceBaseComponentType` traverses down a nested type and replaces the
base type.
``` cpp
using NestedVec = vtkm::Vec<vtkm::Vec<vtkm::Float32, 3>, 8>;
// NewVec1 becomes vtkm::Vec<vtkm::Float64, 8>
using NewVec1 =
typename vtkm::VecTraits<NestedVec>::template ReplaceComponentType<vtkm::Float64>;
// NewVec2 becomes vtkm::Vec<vtkm::Vec<vtkm::Float64, 3>, 8>
using NewVec1 =
typename vtkm::VecTraits<NestedVec>::template ReplaceBaseComponentType<vtkm::Float64>;
```

@ -541,6 +541,7 @@ private:
public:
using ComponentType = T;
using BaseComponentType = typename vtkm::VecTraits<T>::BaseComponentType;
static constexpr vtkm::IdComponent NUM_COMPONENTS = NumRow * NumCol;
using HasMultipleComponents = vtkm::VecTraitsTagMultipleComponents;
using IsSizeStatic = vtkm::VecTraitsTagSizeStatic;
@ -567,6 +568,15 @@ public:
{
GetComponent(matrix, component) = value;
}
template <typename NewComponentType>
using ReplaceComponentType = vtkm::Matrix<NewComponentType, NumRow, NumCol>;
template <typename NewComponentType>
using ReplaceBaseComponentType =
vtkm::Matrix<typename vtkm::VecTraits<T>::template ReplaceBaseComponentType<NewComponentType>,
NumRow,
NumCol>;
};
//---------------------------------------------------------------------------

@ -147,6 +147,7 @@ struct VecTraits<vtkm::VecAxisAlignedPointCoordinates<NumDimensions>>
using VecType = vtkm::VecAxisAlignedPointCoordinates<NumDimensions>;
using ComponentType = vtkm::Vec3f;
using BaseComponentType = vtkm::FloatDefault;
using HasMultipleComponents = vtkm::VecTraitsTagMultipleComponents;
using IsSizeStatic = vtkm::VecTraitsTagSizeStatic;
@ -161,6 +162,13 @@ struct VecTraits<vtkm::VecAxisAlignedPointCoordinates<NumDimensions>>
return vector[componentIndex];
}
// These are a bit of a hack since VecAxisAlignedPointCoordinates only supports one component
// type. Using these might not work as expected.
template <typename NewComponentType>
using ReplaceComponentType = vtkm::Vec<NewComponentType, NUM_COMPONENTS>;
template <typename NewComponentType>
using ReplaceBaseComponenttype = vtkm::Vec<vtkm::Vec<NewComponentType, 3>, NUM_COMPONENTS>;
template <vtkm::IdComponent destSize>
VTKM_EXEC_CONT static void CopyInto(const VecType& src, vtkm::Vec<ComponentType, destSize>& dest)
{

@ -99,6 +99,7 @@ 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;

@ -136,6 +136,7 @@ struct VecTraits<vtkm::VecFromPortalPermute<IndexVecType, PortalType>>
using VecType = vtkm::VecFromPortalPermute<IndexVecType, PortalType>;
using ComponentType = typename VecType::ComponentType;
using BaseComponentType = typename vtkm::VecTraits<ComponentType>::BaseComponentType;
using HasMultipleComponents = vtkm::VecTraitsTagMultipleComponents;
using IsSizeStatic = vtkm::VecTraitsTagSizeVariable;

@ -66,10 +66,19 @@ template <class VecType>
struct VTKM_NEVER_EXPORT VecTraits
{
#ifdef VTKM_DOXYGEN_ONLY
/// Type of the components in the vector.
/// \brief Type of the components in the vector.
///
/// If the type is really a scalar, then the component type is the same as the scalar type.
///
using ComponentType = typename VecType::ComponentType;
/// \brief Base component type in the vector.
///
/// Similar to ComponentType except that for nested vectors (e.g. Vec<Vec<T, M>, N>), it
/// returns the base scalar type at the end of the composition (T in this example).
///
using BaseComponentType = typename vtkm::VecTraits<ComponentType>::BaseComponentType;
/// \brief Number of components in the vector.
///
/// This is only defined for vectors of a static size.
@ -111,6 +120,27 @@ struct VTKM_NEVER_EXPORT VecTraits
vtkm::IdComponent component,
ComponentType value);
/// \brief Get a vector of the same type but with a different component.
///
/// This type resolves to another vector with a different component type. For example,
/// vtkm::VecTraits<vtkm::Vec<T, N>>::ReplaceComponentType<T2> is vtkm::Vec<T2, N>.
/// This replacement is not recursive. So VecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2>
/// is vtkm::Vec<T2, N>.
///
template <typename NewComponentType>
using ReplaceComponentType = VecTemplate<NewComponentType, N>;
/// \brief Get a vector of the same type but with a different base component.
///
/// This type resolves to another vector with a different base component type. The replacement
/// is recursive for nested types. For example,
/// VecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2> is Vec<Vec<T2, M>, N>.
///
template <typename NewComponentType>
using ReplaceBaseComponentType = VecTemplate<
typename VecTraits<ComponentType>::template ReplaceBaseComponentType<NewComponentType>,
N>;
/// Copies the components in the given vector into a given Vec object.
///
template <vktm::IdComponent destSize>
@ -158,10 +188,19 @@ struct VTKM_NEVER_EXPORT VecTraits<vtkm::Vec<T, Size>>
{
using VecType = vtkm::Vec<T, Size>;
/// Type of the components in the vector.
/// \brief Type of the components in the vector.
///
/// If the type is really a scalar, then the component type is the same as the scalar type.
///
using ComponentType = typename VecType::ComponentType;
/// \brief Base component type in the vector.
///
/// Similar to ComponentType except that for nested vectors (e.g. Vec<Vec<T, M>, N>), it
/// returns the base scalar type at the end of the composition (T in this example).
///
using BaseComponentType = typename vtkm::VecTraits<ComponentType>::BaseComponentType;
/// Number of components in the vector.
///
static constexpr vtkm::IdComponent NUM_COMPONENTS = VecType::NUM_COMPONENTS;
@ -208,6 +247,27 @@ struct VTKM_NEVER_EXPORT VecTraits<vtkm::Vec<T, Size>>
vector[component] = value;
}
/// \brief Get a vector of the same type but with a different component.
///
/// This type resolves to another vector with a different component type. For example,
/// vtkm::VecTraits<vtkm::Vec<T, N>>::ReplaceComponentType<T2> is vtkm::Vec<T2, N>.
/// This replacement is not recursive. So VecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2>
/// is vtkm::Vec<T2, N>.
///
template <typename NewComponentType>
using ReplaceComponentType = vtkm::Vec<NewComponentType, Size>;
/// \brief Get a vector of the same type but with a different base component.
///
/// This type resolves to another vector with a different base component type. The replacement
/// is recursive for nested types. For example,
/// VecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2> is Vec<Vec<T2, M>, N>.
///
template <typename NewComponentType>
using ReplaceBaseComponentType = vtkm::Vec<
typename vtkm::VecTraits<ComponentType>::template ReplaceBaseComponentType<NewComponentType>,
Size>;
/// Converts whatever type this vector is into the standard VTKm Tuple.
///
template <vtkm::IdComponent destSize>
@ -222,10 +282,19 @@ struct VTKM_NEVER_EXPORT VecTraits<vtkm::VecC<T>>
{
using VecType = vtkm::VecC<T>;
/// Type of the components in the vector.
/// \brief Type of the components in the vector.
///
/// If the type is really a scalar, then the component type is the same as the scalar type.
///
using ComponentType = typename VecType::ComponentType;
/// \brief Base component type in the vector.
///
/// Similar to ComponentType except that for nested vectors (e.g. Vec<Vec<T, M>, N>), it
/// returns the base scalar type at the end of the composition (T in this example).
///
using BaseComponentType = typename vtkm::VecTraits<ComponentType>::BaseComponentType;
/// Number of components in the given vector.
///
VTKM_EXEC_CONT
@ -273,6 +342,26 @@ struct VTKM_NEVER_EXPORT VecTraits<vtkm::VecC<T>>
vector[component] = value;
}
/// \brief Get a vector of the same type but with a different component.
///
/// This type resolves to another vector with a different component type. For example,
/// vtkm::VecTraits<vtkm::Vec<T, N>>::ReplaceComponentType<T2> is vtkm::Vec<T2, N>.
/// This replacement is not recursive. So VecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2>
/// is vtkm::Vec<T2, N>.
///
template <typename NewComponentType>
using ReplaceComponentType = vtkm::VecC<NewComponentType>;
/// \brief Get a vector of the same type but with a different base component.
///
/// This type resolves to another vector with a different base component type. The replacement
/// is recursive for nested types. For example,
/// VecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2> is Vec<Vec<T2, M>, N>.
///
template <typename NewComponentType>
using ReplaceBaseComponentType = vtkm::VecC<
typename vtkm::VecTraits<ComponentType>::template ReplaceBaseComponentType<NewComponentType>>;
/// Converts whatever type this vector is into the standard VTKm Tuple.
///
template <vtkm::IdComponent destSize>
@ -287,10 +376,19 @@ struct VTKM_NEVER_EXPORT VecTraits<vtkm::VecCConst<T>>
{
using VecType = vtkm::VecCConst<T>;
/// Type of the components in the vector.
/// \brief Type of the components in the vector.
///
/// If the type is really a scalar, then the component type is the same as the scalar type.
///
using ComponentType = typename VecType::ComponentType;
/// \brief Base component type in the vector.
///
/// Similar to ComponentType except that for nested vectors (e.g. Vec<Vec<T, M>, N>), it
/// returns the base scalar type at the end of the composition (T in this example).
///
using BaseComponentType = typename vtkm::VecTraits<ComponentType>::BaseComponentType;
/// Number of components in the given vector.
///
VTKM_EXEC_CONT
@ -333,6 +431,26 @@ struct VTKM_NEVER_EXPORT VecTraits<vtkm::VecCConst<T>>
vector[component] = value;
}
/// \brief Get a vector of the same type but with a different component.
///
/// This type resolves to another vector with a different component type. For example,
/// vtkm::VecTraits<vtkm::Vec<T, N>>::ReplaceComponentType<T2> is vtkm::Vec<T2, N>.
/// This replacement is not recursive. So VecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2>
/// is vtkm::Vec<T2, N>.
///
template <typename NewComponentType>
using ReplaceComponentType = vtkm::VecCConst<NewComponentType>;
/// \brief Get a vector of the same type but with a different base component.
///
/// This type resolves to another vector with a different base component type. The replacement
/// is recursive for nested types. For example,
/// VecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2> is Vec<Vec<T2, M>, N>.
///
template <typename NewComponentType>
using ReplaceBaseComponentType = vtkm::VecCConst<
typename vtkm::VecTraits<ComponentType>::template ReplaceBaseComponentType<NewComponentType>>;
/// Converts whatever type this vector is into the standard VTKm Tuple.
///
template <vtkm::IdComponent destSize>
@ -350,6 +468,7 @@ template <typename ScalarType>
struct VTKM_NEVER_EXPORT VecTraitsBasic
{
using ComponentType = ScalarType;
using BaseComponentType = ScalarType;
static constexpr vtkm::IdComponent NUM_COMPONENTS = 1;
using HasMultipleComponents = vtkm::VecTraitsTagSingleComponent;
using IsSizeStatic = vtkm::VecTraitsTagSizeStatic;
@ -372,6 +491,12 @@ struct VTKM_NEVER_EXPORT VecTraitsBasic
vector = value;
}
template <typename NewComponentType>
using ReplaceComponentType = NewComponentType;
template <typename NewComponentType>
using ReplaceBaseComponentType = NewComponentType;
template <vtkm::IdComponent destSize>
VTKM_EXEC_CONT static void CopyInto(const ScalarType& src, vtkm::Vec<ScalarType, destSize>& dest)
{

@ -103,6 +103,7 @@ struct VecTraits<vtkm::VecVariable<T, MaxSize>>
using VecType = vtkm::VecVariable<T, MaxSize>;
using ComponentType = typename VecType::ComponentType;
using BaseComponentType = typename vtkm::VecTraits<ComponentType>::BaseComponentType;
using HasMultipleComponents = vtkm::VecTraitsTagMultipleComponents;
using IsSizeStatic = vtkm::VecTraitsTagSizeVariable;
@ -131,6 +132,14 @@ struct VecTraits<vtkm::VecVariable<T, MaxSize>>
vector[componentIndex] = value;
}
template <typename NewComponentType>
using ReplaceComponentType = vtkm::VecVariable<NewComponentType, MaxSize>;
template <typename NewComponentType>
using ReplaceBaseComponentType = vtkm::VecVariable<
typename vtkm::VecTraits<ComponentType>::template ReplaceBaseComponentType<NewComponentType>,
MaxSize>;
template <vtkm::IdComponent destSize>
VTKM_EXEC_CONT static void CopyInto(const VecType& src, vtkm::Vec<ComponentType, destSize>& dest)
{

@ -25,6 +25,7 @@
#include <vtkm/VecTraits.h>
#include <vtkm/StaticAssert.h>
#include <vtkm/TypeTraits.h>
#include <vtkm/testing/Testing.h>
@ -154,6 +155,40 @@ static void TestVecTypeImpl(const typename std::remove_const<T>::type& inVector,
TestVecTypeWritableImpl<NUM_COMPONENTS, NonConstT>(
inVector, vectorCopy, outVector, typename VecIsWritable<NonConstT>::type());
// Compiler checks for base component types
using BaseComponentType = typename vtkm::VecTraits<T>::BaseComponentType;
VTKM_STATIC_ASSERT((std::is_same<typename vtkm::TypeTraits<BaseComponentType>::DimensionalityTag,
vtkm::TypeTraitsScalarTag>::value));
VTKM_STATIC_ASSERT((std::is_same<typename vtkm::VecTraits<ComponentType>::BaseComponentType,
BaseComponentType>::value));
// Compiler checks for replacing component types
using ReplaceWithVecComponent =
typename vtkm::VecTraits<T>::template ReplaceComponentType<vtkm::Vec<char, 2>>;
VTKM_STATIC_ASSERT(
(std::is_same<typename vtkm::TypeTraits<T>::DimensionalityTag,
vtkm::TypeTraitsVectorTag>::value &&
std::is_same<typename vtkm::VecTraits<ReplaceWithVecComponent>::ComponentType,
vtkm::Vec<char, 2>>::value) ||
(std::is_same<typename vtkm::TypeTraits<T>::DimensionalityTag,
vtkm::TypeTraitsScalarTag>::value &&
std::is_same<typename vtkm::VecTraits<ReplaceWithVecComponent>::ComponentType, char>::value));
VTKM_STATIC_ASSERT(
(std::is_same<typename vtkm::VecTraits<ReplaceWithVecComponent>::BaseComponentType,
char>::value));
using ReplaceBaseComponent =
typename vtkm::VecTraits<ReplaceWithVecComponent>::template ReplaceBaseComponentType<short>;
VTKM_STATIC_ASSERT(
(std::is_same<typename vtkm::TypeTraits<T>::DimensionalityTag,
vtkm::TypeTraitsVectorTag>::value &&
std::is_same<typename vtkm::VecTraits<ReplaceBaseComponent>::ComponentType,
vtkm::Vec<short, 2>>::value) ||
(std::is_same<typename vtkm::TypeTraits<T>::DimensionalityTag,
vtkm::TypeTraitsScalarTag>::value &&
std::is_same<typename vtkm::VecTraits<ReplaceBaseComponent>::ComponentType, short>::value));
VTKM_STATIC_ASSERT((
std::is_same<typename vtkm::VecTraits<ReplaceBaseComponent>::BaseComponentType, short>::value));
}
inline void CheckVecComponentsTag(vtkm::VecTraitsTagMultipleComponents)