Add support for getting vec sizes of unknown arrays when runtime selected

The `GetNumberOfComponents` and `GetNumberOfComponentsFlat` methods in
`UnknownArrayHandle` have been updated to correctly report the number of
components in special `ArrayHandle`s where the `Vec` sizes of the values
are not selected until runtime.

Previously, these methods always reported 0 because the value type could
not report the size of the `Vec`. The lookup has been modified to query the
`ArrayHandle`'s `Storage` for the number of components where supported.
Note that this only works on `Storage` that provides a method to get the
runtime `Vec` size. If that is not provided, as will be the case if the
number of components can vary from one value to the next, it will still
report 0.

This feature is implemented by looking for a method named
`GetNumberOfComponents` is the `Storage` class for the `ArrayHandle`. If
this method is found, it is used to query the size at runtime.
This commit is contained in:
Kenneth Moreland 2023-02-09 09:42:38 -07:00
parent a4517e70b0
commit a80de8019a
4 changed files with 104 additions and 47 deletions

@ -0,0 +1,18 @@
# Added support for getting vec sizes of unknown arrays when runtime selected
The `GetNumberOfComponents` and `GetNumberOfComponentsFlat` methods in
`UnknownArrayHandle` have been updated to correctly report the number of
components in special `ArrayHandle`s where the `Vec` sizes of the values
are not selected until runtime.
Previously, these methods always reported 0 because the value type could
not report the size of the `Vec`. The lookup has been modified to query the
`ArrayHandle`'s `Storage` for the number of components where supported.
Note that this only works on `Storage` that provides a method to get the
runtime `Vec` size. If that is not provided, as will be the case if the
number of components can vary from one value to the next, it will still
report 0.
This feature is implemented by looking for a method named
`GetNumberOfComponents` is the `Storage` class for the `ArrayHandle`. If
this method is found, it is used to query the size at runtime.

@ -437,7 +437,7 @@ public:
using ReadPortalType = vtkm::internal::ArrayPortalRecombineVec<ReadWritePortal>;
using WritePortalType = vtkm::internal::ArrayPortalRecombineVec<ReadWritePortal>;
VTKM_CONT static vtkm::IdComponent NumberOfComponents(
VTKM_CONT static vtkm::IdComponent GetNumberOfComponents(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return static_cast<vtkm::IdComponent>(
@ -455,7 +455,7 @@ public:
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
vtkm::IdComponent numComponents = NumberOfComponents(buffers);
vtkm::IdComponent numComponents = GetNumberOfComponents(buffers);
for (vtkm::IdComponent component = 0; component < numComponents; ++component)
{
SourceStorage::ResizeBuffers(
@ -477,7 +477,7 @@ public:
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
vtkm::IdComponent numComponents = NumberOfComponents(buffers);
vtkm::IdComponent numComponents = GetNumberOfComponents(buffers);
// The array portal needs a runtime-allocated array of portals for each component.
// We use the vtkm::cont::internal::Buffer object to allow us to allocate memory on the
@ -515,7 +515,7 @@ public:
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
vtkm::IdComponent numComponents = NumberOfComponents(buffers);
vtkm::IdComponent numComponents = GetNumberOfComponents(buffers);
// The array portal needs a runtime-allocated array of portals for each component.
// We use the vtkm::cont::internal::Buffer object to allow us to allocate memory on the
@ -608,7 +608,7 @@ private:
public:
vtkm::IdComponent GetNumberOfComponents() const
{
return StorageType::NumberOfComponents(this->GetBuffers());
return StorageType::GetNumberOfComponents(this->GetBuffers());
}
vtkm::cont::ArrayHandleStride<ComponentType> GetComponentArray(

@ -265,7 +265,7 @@ vtkm::IdComponent UnknownArrayHandle::GetNumberOfComponents() const
{
if (this->Container)
{
return this->Container->NumberOfComponents();
return this->Container->NumberOfComponents(this->Container->ArrayHandlePointer);
}
else
{
@ -277,7 +277,7 @@ VTKM_CONT vtkm::IdComponent UnknownArrayHandle::GetNumberOfComponentsFlat() cons
{
if (this->Container)
{
return this->Container->NumberOfComponentsFlat();
return this->Container->NumberOfComponentsFlat(this->Container->ArrayHandlePointer);
}
else
{

@ -56,49 +56,88 @@ vtkm::Id UnknownAHNumberOfValues(void* mem)
return arrayHandle->GetNumberOfValues();
}
template <typename T, typename StaticSize = typename vtkm::internal::SafeVecTraits<T>::IsSizeStatic>
struct UnknownAHNumberOfComponentsImpl;
template <typename T>
struct UnknownAHNumberOfComponentsImpl<T, vtkm::VecTraitsTagSizeStatic>
// Uses SFINAE to use Storage<>::GetNumberOfComponents if it exists, or the VecTraits otherwise
template <typename T, typename S>
inline auto UnknownAHNumberOfComponentsImpl(void* mem)
-> decltype(vtkm::cont::internal::Storage<T, S>::GetNumberOfComponents(
std::vector<vtkm::cont::internal::Buffer>()))
{
static constexpr vtkm::IdComponent Value = vtkm::internal::SafeVecTraits<T>::NUM_COMPONENTS;
};
template <typename T>
struct UnknownAHNumberOfComponentsImpl<T, vtkm::VecTraitsTagSizeVariable>
{
static constexpr vtkm::IdComponent Value = 0;
};
template <typename T>
vtkm::IdComponent UnknownAHNumberOfComponents()
{
return UnknownAHNumberOfComponentsImpl<T>::Value;
using AH = vtkm::cont::ArrayHandle<T, S>;
AH* arrayHandle = reinterpret_cast<AH*>(mem);
return vtkm::cont::internal::Storage<T, S>::GetNumberOfComponents(arrayHandle->GetBuffers());
}
template <typename T,
typename = typename vtkm::internal::SafeVecTraits<T>::IsSizeStatic,
typename = vtkm::HasVecTraits<T>>
struct UnknownAHNumberOfComponentsFlatImpl;
template <typename T>
struct UnknownAHNumberOfComponentsFlatImpl<T, vtkm::VecTraitsTagSizeStatic, std::true_type>
// Uses SFINAE to use the number of compnents in VecTraits.
// Note that this will conflict with the above overloaded function if the storage has a
// GetNumberOfComponents method and VecTraits has a static size. However, I cannot think
// of a use case for the storage to report the number of components for a static data type.
// If that happens, this implementation will need to be modified.
template <typename T, typename S>
inline auto UnknownAHNumberOfComponentsImpl(void*)
-> decltype(vtkm::internal::SafeVecTraits<T>::NUM_COMPONENTS)
{
static constexpr vtkm::IdComponent Value = vtkm::VecFlat<T>::NUM_COMPONENTS;
};
template <typename T>
struct UnknownAHNumberOfComponentsFlatImpl<T, vtkm::VecTraitsTagSizeVariable, std::true_type>
{
static constexpr vtkm::IdComponent Value = 0;
};
template <typename T>
struct UnknownAHNumberOfComponentsFlatImpl<T, vtkm::VecTraitsTagSizeStatic, std::false_type>
{
static constexpr vtkm::IdComponent Value = 1;
};
static constexpr vtkm::IdComponent numComponents =
vtkm::internal::SafeVecTraits<T>::NUM_COMPONENTS;
return numComponents;
}
template <typename T>
vtkm::IdComponent UnknownAHNumberOfComponentsFlat()
// Fallback for when there is no way to determine the number of components. (This could be
// because each value could have a different number of components.
template <typename T, typename S>
inline vtkm::IdComponent UnknownAHNumberOfComponentsImpl(...)
{
return UnknownAHNumberOfComponentsFlatImpl<T>::Value;
return 0;
}
template <typename T, typename S>
vtkm::IdComponent UnknownAHNumberOfComponents(void* mem)
{
return UnknownAHNumberOfComponentsImpl<T, S>(mem);
}
// Uses SFINAE to use Storage<>::GetNumberOfComponents if it exists, or the VecTraits otherwise
template <typename T, typename S>
inline auto UnknownAHNumberOfComponentsFlatImpl(void* mem)
-> decltype(vtkm::cont::internal::Storage<T, S>::GetNumberOfComponents(
std::vector<vtkm::cont::internal::Buffer>()))
{
using AH = vtkm::cont::ArrayHandle<T, S>;
AH* arrayHandle = reinterpret_cast<AH*>(mem);
// Making an assumption here that `T` is a `Vec`-like object that `GetNumberOfComponents`
// will report on how many each has. Further assuming that the components of `T` are
// static. If a future `ArrayHandle` type violates this, this code will have to become
// more complex.
return (vtkm::cont::internal::Storage<T, S>::GetNumberOfComponents(arrayHandle->GetBuffers()) *
vtkm::VecFlat<typename vtkm::internal::SafeVecTraits<T>::ComponentType>::NUM_COMPONENTS);
}
// Uses SFINAE to use the number of compnents in VecTraits.
// Note that this will conflict with the above overloaded function if the storage has a
// GetNumberOfComponents method and VecTraits has a static size. However, I cannot think
// of a use case for the storage to report the number of components for a static data type.
// If that happens, this implementation will need to be modified.
template <typename T, typename S>
inline auto UnknownAHNumberOfComponentsFlatImpl(void*)
-> decltype(vtkm::VecTraits<T>::NUM_COMPONENTS)
{
// static constexpr vtkm::IdComponent numComponents = vtkm::VecFlat<T>::NUM_COMPONENTS;
// return numComponents;
return vtkm::VecFlat<T>::NUM_COMPONENTS;
}
// Fallback for when there is no way to determine the number of components. (This could be
// because each value could have a different number of components or just that VecTraits
// are not defined.) Since it cannot be flattened, just return the same as num components.
template <typename T, typename S>
inline vtkm::IdComponent UnknownAHNumberOfComponentsFlatImpl(...)
{
return UnknownAHNumberOfComponentsImpl<T, S>(static_cast<void*>(nullptr));
}
template <typename T, typename S>
vtkm::IdComponent UnknownAHNumberOfComponentsFlat(void* mem)
{
return UnknownAHNumberOfComponentsFlatImpl<T, S>(mem);
}
template <typename T, typename S>
@ -230,7 +269,7 @@ struct VTKM_CONT_EXPORT UnknownAHContainer
using NumberOfValuesType = vtkm::Id(void*);
NumberOfValuesType* NumberOfValues;
using NumberOfComponentsType = vtkm::IdComponent();
using NumberOfComponentsType = vtkm::IdComponent(void*);
NumberOfComponentsType* NumberOfComponents;
NumberOfComponentsType* NumberOfComponentsFlat;
@ -348,8 +387,8 @@ inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle<T, S
, NewInstanceBasic(detail::UnknownAHNewInstanceBasic<T>)
, NewInstanceFloatBasic(detail::UnknownAHNewInstanceFloatBasic<T>)
, NumberOfValues(detail::UnknownAHNumberOfValues<T, S>)
, NumberOfComponents(detail::UnknownAHNumberOfComponents<T>)
, NumberOfComponentsFlat(detail::UnknownAHNumberOfComponentsFlat<T>)
, NumberOfComponents(detail::UnknownAHNumberOfComponents<T, S>)
, NumberOfComponentsFlat(detail::UnknownAHNumberOfComponentsFlat<T, S>)
, Allocate(detail::UnknownAHAllocate<T, S>)
, ShallowCopy(detail::UnknownAHShallowCopy<T, S>)
, DeepCopy(detail::UnknownAHDeepCopy<T, S>)