diff --git a/vtkm/cont/ArrayCopy.h b/vtkm/cont/ArrayCopy.h index 522720a24..f19c29bf9 100644 --- a/vtkm/cont/ArrayCopy.h +++ b/vtkm/cont/ArrayCopy.h @@ -10,8 +10,15 @@ #ifndef vtk_m_cont_ArrayCopy_h #define vtk_m_cont_ArrayCopy_h +#include +#include +#include +#include +#include #include +#include + #include #include @@ -38,6 +45,70 @@ inline void ArrayCopyValueTypeCheck() "see the offending type."); } +template +struct ArrayCopyConcreteSrc; + +template +inline void ArrayCopyImpl(const vtkm::cont::UnknownArrayHandle& source, + vtkm::cont::UnknownArrayHandle& destination, + SrcIsArrayHandle, + std::false_type) +{ + destination.DeepCopyFrom(source); +} +template +inline void ArrayCopyImpl(const vtkm::cont::UnknownArrayHandle& source, + const vtkm::cont::UnknownArrayHandle& destination, + SrcIsArrayHandle, + std::false_type) +{ + destination.DeepCopyFrom(source); +} + +template +void ArrayCopyImpl(const vtkm::cont::UnknownArrayHandle& source, + vtkm::cont::ArrayHandle& destination, + std::false_type, + std::true_type) +{ + detail::ArrayCopyValueTypeCheck(); + + using DestType = vtkm::cont::ArrayHandle; + if (source.CanConvert()) + { + destination.DeepCopyFrom(source.AsArrayHandle()); + } + else + { + vtkm::cont::UnknownArrayHandle destWrapper(destination); + vtkm::cont::detail::ArrayCopyImpl(source, destWrapper, std::false_type{}, std::false_type{}); + // Destination array should not change, but just in case. + destWrapper.AsArrayHandle(destination); + } +} + +template +void ArrayCopyImpl(const vtkm::cont::ArrayHandle& source, + vtkm::cont::ArrayHandle& destination, + std::true_type, + std::true_type) +{ + ArrayCopyValueTypeCheck(); + ArrayCopyValueTypeCheck(); + + detail::ArrayCopyConcreteSrc{}(source, destination); +} + +// Special case of copying data when type is the same. +template +void ArrayCopyImpl(const vtkm::cont::ArrayHandle& source, + vtkm::cont::ArrayHandle& destination, + std::true_type, + std::true_type) +{ + destination.DeepCopyFrom(source); +} + } /// \brief Does a deep copy from one array to another array. @@ -64,51 +135,23 @@ inline void ArrayCopyValueTypeCheck() /// /// @{ /// -inline void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source, - vtkm::cont::UnknownArrayHandle& destination) +template +inline void ArrayCopy(const SourceArrayType& source, DestArrayType& destination) { - destination.DeepCopyFrom(source); -} -inline void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source, - const vtkm::cont::UnknownArrayHandle& destination) -{ - destination.DeepCopyFrom(source); + detail::ArrayCopyImpl(source, + destination, + typename internal::ArrayHandleCheck::type{}, + typename internal::ArrayHandleCheck::type{}); } -template -void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source, - vtkm::cont::ArrayHandle& destination) +// Special case where we allow a const UnknownArrayHandle as output. +template +inline void ArrayCopy(const SourceArrayType& source, vtkm::cont::UnknownArrayHandle& destination) { - detail::ArrayCopyValueTypeCheck(); - - using DestType = vtkm::cont::ArrayHandle; - if (source.CanConvert()) - { - destination.DeepCopyFrom(source.AsArrayHandle()); - } - else - { - vtkm::cont::UnknownArrayHandle destWrapper(destination); - vtkm::cont::ArrayCopy(source, destWrapper); - // Destination array should not change, but just in case. - destWrapper.AsArrayHandle(destination); - } -} - -template -void ArrayCopy(const vtkm::cont::ArrayHandle& source, DestArray& destination) -{ - detail::ArrayCopyValueTypeCheck(); - - vtkm::cont::ArrayCopy(vtkm::cont::UnknownArrayHandle{ source }, destination); -} - -// Special case of copying data when type is the same. -template -void ArrayCopy(const vtkm::cont::ArrayHandle& source, - vtkm::cont::ArrayHandle& destination) -{ - destination.DeepCopyFrom(source); + detail::ArrayCopyImpl(source, + destination, + typename internal::ArrayHandleCheck::type{}, + std::false_type{}); } // Invalid const ArrayHandle in destination, which is not allowed because it will @@ -150,6 +193,111 @@ VTKM_CONT void ArrayCopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle s } } +namespace detail +{ + +template +struct ArrayCopyConcreteSrc +{ + template + void operator()(const vtkm::cont::ArrayHandle& source, DestArray& destination) const + { + using ArrayType = vtkm::cont::ArrayHandle; + this->DoIt( + source, destination, vtkm::cont::internal::ArrayExtractComponentIsInefficient{}); + } + + template + void DoIt(const vtkm::cont::ArrayHandle& source, + DestArray& destination, + std::false_type vtkmNotUsed(isInefficient)) const + { + vtkm::cont::ArrayCopy(vtkm::cont::UnknownArrayHandle{ source }, destination); + } + + template + void DoIt(const vtkm::cont::ArrayHandle& source, + DestArray& destination, + std::true_type vtkmNotUsed(isInefficient)) const + { + VTKM_LOG_S(vtkm::cont::LogLevel::Warn, + "Attempting to copy from an array of type " + + vtkm::cont::TypeToString>() + + " with ArrayCopy is inefficient. It is highly recommended you use another method " + "such as vtkm::cont::ArrayCopyDevice."); + // Still call the precompiled `ArrayCopy`. You will get another warning after this, + // but it will still technically work, albiet slowly. + vtkm::cont::ArrayCopy(vtkm::cont::UnknownArrayHandle{ source }, destination); + } +}; + +// Special case for constant arrays to be efficient. +template <> +struct ArrayCopyConcreteSrc +{ + template + void operator()(const vtkm::cont::ArrayHandle& source_, + vtkm::cont::ArrayHandle& destination) const + { + vtkm::cont::ArrayHandleConstant source = source_; + destination.AllocateAndFill(source.GetNumberOfValues(), static_cast(source.GetValue())); + } +}; + +// Special case for ArrayHandleIndex to be efficient. +template <> +struct ArrayCopyConcreteSrc +{ + template + void operator()(const vtkm::cont::ArrayHandleIndex& source, + vtkm::cont::ArrayHandle& destination) const + { + // Skip warning about inefficient copy because there is a special case in ArrayCopyUnknown.cxx + // to copy ArrayHandleIndex efficiently. + vtkm::cont::ArrayCopy(vtkm::cont::UnknownArrayHandle{ source }, destination); + } +}; + +// Special case for ArrayHandleConcatenate to be efficient +template +struct ArrayCopyConcreteSrc> +{ + template + void operator()(const SourceArrayType& source, DestArrayType& destination) const + { + auto source1 = source.GetStorage().GetArray1(source.GetBuffers()); + auto source2 = source.GetStorage().GetArray2(source.GetBuffers()); + + // Need to preallocate because view decorator will not be able to resize. + destination.Allocate(source.GetNumberOfValues()); + auto dest1 = vtkm::cont::make_ArrayHandleView(destination, 0, source1.GetNumberOfValues()); + auto dest2 = vtkm::cont::make_ArrayHandleView( + destination, source1.GetNumberOfValues(), source2.GetNumberOfValues()); + + vtkm::cont::ArrayCopy(source1, dest1); + vtkm::cont::ArrayCopy(source2, dest2); + } +}; + +// Special case for ArrayHandlePermutation to be efficient +template +struct ArrayCopyConcreteSrc> +{ + using SourceStorageTag = vtkm::cont::StorageTagPermutation; + template + void operator()(const vtkm::cont::ArrayHandle& source, + vtkm::cont::ArrayHandle& destination) const + { + auto indexArray = source.GetStorage().GetIndexArray(source.GetBuffers()); + auto valueArray = source.GetStorage().GetValueArray(source.GetBuffers()); + vtkm::cont::UnknownArrayHandle copy = + vtkm::cont::internal::MapArrayPermutation(valueArray, indexArray); + vtkm::cont::ArrayCopyShallowIfPossible(copy, destination); + } +}; + +} // namespace detail + } // namespace cont } // namespace vtkm diff --git a/vtkm/cont/ArrayHandleConcatenate.h b/vtkm/cont/ArrayHandleConcatenate.h index b29d7abaa..866ad8092 100644 --- a/vtkm/cont/ArrayHandleConcatenate.h +++ b/vtkm/cont/ArrayHandleConcatenate.h @@ -248,12 +248,12 @@ public: return vtkm::cont::internal::CreateBuffers(array1, array2); } - VTKM_CONT static const ArrayHandleType1& GetArray1(const vtkm::cont::internal::Buffer* buffers) + VTKM_CONT static const ArrayHandleType1 GetArray1(const vtkm::cont::internal::Buffer* buffers) { return ArrayHandleType1(Buffers1(buffers)); } - VTKM_CONT static const ArrayHandleType2& GetArray2(const vtkm::cont::internal::Buffer* buffers) + VTKM_CONT static const ArrayHandleType2 GetArray2(const vtkm::cont::internal::Buffer* buffers) { return ArrayHandleType2(Buffers2(buffers)); } diff --git a/vtkm/cont/internal/ArrayCopyUnknown.cxx b/vtkm/cont/internal/ArrayCopyUnknown.cxx index a837c4ff1..fdee4befc 100644 --- a/vtkm/cont/internal/ArrayCopyUnknown.cxx +++ b/vtkm/cont/internal/ArrayCopyUnknown.cxx @@ -9,6 +9,8 @@ //============================================================================ #include +#include +#include #include #include @@ -145,11 +147,68 @@ struct UnknownCopyFunctor1 } }; +void ArrayCopySpecialCase(const vtkm::cont::ArrayHandleIndex& source, + const vtkm::cont::UnknownArrayHandle& destination) +{ + if (destination.CanConvert()) + { + // Unlikely, but we'll check. + destination.AsArrayHandle().DeepCopyFrom(source); + } + else if (destination.IsBaseComponentType()) + { + destination.Allocate(source.GetNumberOfValues()); + auto dest = destination.ExtractComponent(0, vtkm::CopyFlag::Off); + vtkm::cont::ArrayCopyDevice(source, dest); + } + else if (destination.IsBaseComponentType()) + { + destination.Allocate(source.GetNumberOfValues()); + auto dest = destination.ExtractComponent(0, vtkm::CopyFlag::Off); + vtkm::cont::ArrayCopyDevice(source, dest); + } + else if (destination.CanConvert>()) + { + vtkm::cont::ArrayHandle dest; + destination.AsArrayHandle(dest); + vtkm::cont::ArrayCopyDevice(source, dest); + } + else + { + // Initializing something that is probably not really an index. Rather than trace down every + // unlikely possibility, just copy to float and then to the final array. + vtkm::cont::ArrayHandle dest; + vtkm::cont::ArrayCopyDevice(source, dest); + vtkm::cont::ArrayCopy(dest, destination); + } +} + +template +bool TryArrayCopySpecialCase(const vtkm::cont::UnknownArrayHandle& source, + const vtkm::cont::UnknownArrayHandle& destination) +{ + if (source.CanConvert()) + { + ArrayCopySpecialCase(source.AsArrayHandle(), destination); + return true; + } + else + { + return false; + } +} + void DoUnknownArrayCopy(const vtkm::cont::UnknownArrayHandle& source, const vtkm::cont::UnknownArrayHandle& destination) { if (source.GetNumberOfValues() > 0) { + // Try known special cases. + if (TryArrayCopySpecialCase(source, destination)) + { + return; + } + source.CastAndCallWithExtractedArray(UnknownCopyFunctor1{}, destination); } else