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)