From a80de8019aaff33f7a0cd271fd833d3de1678548 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Thu, 9 Feb 2023 09:42:38 -0700 Subject: [PATCH] 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. --- .../unknownarray-runtime-components.md | 18 +++ vtkm/cont/ArrayHandleRecombineVec.h | 10 +- vtkm/cont/UnknownArrayHandle.cxx | 4 +- vtkm/cont/UnknownArrayHandle.h | 119 ++++++++++++------ 4 files changed, 104 insertions(+), 47 deletions(-) create mode 100644 docs/changelog/unknownarray-runtime-components.md diff --git a/docs/changelog/unknownarray-runtime-components.md b/docs/changelog/unknownarray-runtime-components.md new file mode 100644 index 000000000..86119ee1e --- /dev/null +++ b/docs/changelog/unknownarray-runtime-components.md @@ -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. diff --git a/vtkm/cont/ArrayHandleRecombineVec.h b/vtkm/cont/ArrayHandleRecombineVec.h index 14e971ee8..cb5f6bf80 100644 --- a/vtkm/cont/ArrayHandleRecombineVec.h +++ b/vtkm/cont/ArrayHandleRecombineVec.h @@ -437,7 +437,7 @@ public: using ReadPortalType = vtkm::internal::ArrayPortalRecombineVec; using WritePortalType = vtkm::internal::ArrayPortalRecombineVec; - VTKM_CONT static vtkm::IdComponent NumberOfComponents( + VTKM_CONT static vtkm::IdComponent GetNumberOfComponents( const std::vector& buffers) { return static_cast( @@ -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 GetComponentArray( diff --git a/vtkm/cont/UnknownArrayHandle.cxx b/vtkm/cont/UnknownArrayHandle.cxx index 4fcfb555d..dde409c17 100644 --- a/vtkm/cont/UnknownArrayHandle.cxx +++ b/vtkm/cont/UnknownArrayHandle.cxx @@ -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 { diff --git a/vtkm/cont/UnknownArrayHandle.h b/vtkm/cont/UnknownArrayHandle.h index 3adf055e6..1f8c2b0e6 100644 --- a/vtkm/cont/UnknownArrayHandle.h +++ b/vtkm/cont/UnknownArrayHandle.h @@ -56,49 +56,88 @@ vtkm::Id UnknownAHNumberOfValues(void* mem) return arrayHandle->GetNumberOfValues(); } -template ::IsSizeStatic> -struct UnknownAHNumberOfComponentsImpl; -template -struct UnknownAHNumberOfComponentsImpl +// Uses SFINAE to use Storage<>::GetNumberOfComponents if it exists, or the VecTraits otherwise +template +inline auto UnknownAHNumberOfComponentsImpl(void* mem) + -> decltype(vtkm::cont::internal::Storage::GetNumberOfComponents( + std::vector())) { - static constexpr vtkm::IdComponent Value = vtkm::internal::SafeVecTraits::NUM_COMPONENTS; -}; -template -struct UnknownAHNumberOfComponentsImpl -{ - static constexpr vtkm::IdComponent Value = 0; -}; - -template -vtkm::IdComponent UnknownAHNumberOfComponents() -{ - return UnknownAHNumberOfComponentsImpl::Value; + using AH = vtkm::cont::ArrayHandle; + AH* arrayHandle = reinterpret_cast(mem); + return vtkm::cont::internal::Storage::GetNumberOfComponents(arrayHandle->GetBuffers()); } -template ::IsSizeStatic, - typename = vtkm::HasVecTraits> -struct UnknownAHNumberOfComponentsFlatImpl; -template -struct UnknownAHNumberOfComponentsFlatImpl +// 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 +inline auto UnknownAHNumberOfComponentsImpl(void*) + -> decltype(vtkm::internal::SafeVecTraits::NUM_COMPONENTS) { - static constexpr vtkm::IdComponent Value = vtkm::VecFlat::NUM_COMPONENTS; -}; -template -struct UnknownAHNumberOfComponentsFlatImpl -{ - static constexpr vtkm::IdComponent Value = 0; -}; -template -struct UnknownAHNumberOfComponentsFlatImpl -{ - static constexpr vtkm::IdComponent Value = 1; -}; + static constexpr vtkm::IdComponent numComponents = + vtkm::internal::SafeVecTraits::NUM_COMPONENTS; + return numComponents; +} -template -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 +inline vtkm::IdComponent UnknownAHNumberOfComponentsImpl(...) { - return UnknownAHNumberOfComponentsFlatImpl::Value; + return 0; +} + +template +vtkm::IdComponent UnknownAHNumberOfComponents(void* mem) +{ + return UnknownAHNumberOfComponentsImpl(mem); +} + +// Uses SFINAE to use Storage<>::GetNumberOfComponents if it exists, or the VecTraits otherwise +template +inline auto UnknownAHNumberOfComponentsFlatImpl(void* mem) + -> decltype(vtkm::cont::internal::Storage::GetNumberOfComponents( + std::vector())) +{ + using AH = vtkm::cont::ArrayHandle; + AH* arrayHandle = reinterpret_cast(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::GetNumberOfComponents(arrayHandle->GetBuffers()) * + vtkm::VecFlat::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 +inline auto UnknownAHNumberOfComponentsFlatImpl(void*) + -> decltype(vtkm::VecTraits::NUM_COMPONENTS) +{ + // static constexpr vtkm::IdComponent numComponents = vtkm::VecFlat::NUM_COMPONENTS; + // return numComponents; + return vtkm::VecFlat::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 +inline vtkm::IdComponent UnknownAHNumberOfComponentsFlatImpl(...) +{ + return UnknownAHNumberOfComponentsImpl(static_cast(nullptr)); +} + +template +vtkm::IdComponent UnknownAHNumberOfComponentsFlat(void* mem) +{ + return UnknownAHNumberOfComponentsFlatImpl(mem); } template @@ -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) , NewInstanceFloatBasic(detail::UnknownAHNewInstanceFloatBasic) , NumberOfValues(detail::UnknownAHNumberOfValues) - , NumberOfComponents(detail::UnknownAHNumberOfComponents) - , NumberOfComponentsFlat(detail::UnknownAHNumberOfComponentsFlat) + , NumberOfComponents(detail::UnknownAHNumberOfComponents) + , NumberOfComponentsFlat(detail::UnknownAHNumberOfComponentsFlat) , Allocate(detail::UnknownAHAllocate) , ShallowCopy(detail::UnknownAHShallowCopy) , DeepCopy(detail::UnknownAHDeepCopy)