//============================================================================ // Copyright (c) Kitware, Inc. // All rights reserved. // See LICENSE.txt for details. // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //============================================================================ #ifndef vtk_m_cont_ArrayHandleTransform_h #define vtk_m_cont_ArrayHandleTransform_h #include #include #include #include #include #include #include namespace vtkm { namespace internal { /// Tag used in place of an inverse functor. struct NullFunctorType { }; /// \brief An array portal that transforms a value from another portal. /// template class VTKM_ALWAYS_EXPORT ArrayPortalTransform; template class VTKM_ALWAYS_EXPORT ArrayPortalTransform { public: using PortalType = PortalType_; using ValueType = ValueType_; using FunctorType = FunctorType_; VTKM_EXEC_CONT ArrayPortalTransform(const PortalType& portal = PortalType(), const FunctorType& functor = FunctorType()) : Portal(portal) , Functor(functor) { } /// Copy constructor for any other ArrayPortalTransform with an iterator /// type that can be copied to this iterator type. This allows us to do any /// type casting that the iterators do (like the non-const to const cast). /// template VTKM_EXEC_CONT ArrayPortalTransform(const ArrayPortalTransform& src) : Portal(src.GetPortal()) , Functor(src.GetFunctor()) { } VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const { return this->Portal.GetNumberOfValues(); } VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const { return this->Functor(this->Portal.Get(index)); } VTKM_EXEC_CONT const PortalType& GetPortal() const { return this->Portal; } VTKM_EXEC_CONT const FunctorType& GetFunctor() const { return this->Functor; } protected: PortalType Portal; FunctorType Functor; }; template class VTKM_ALWAYS_EXPORT ArrayPortalTransform : public ArrayPortalTransform { using Writable = vtkm::internal::PortalSupportsSets; public: using Superclass = ArrayPortalTransform; using PortalType = PortalType_; using ValueType = ValueType_; using FunctorType = FunctorType_; using InverseFunctorType = InverseFunctorType_; VTKM_EXEC_CONT ArrayPortalTransform(const PortalType& portal = PortalType(), const FunctorType& functor = FunctorType(), const InverseFunctorType& inverseFunctor = InverseFunctorType()) : Superclass(portal, functor) , InverseFunctor(inverseFunctor) { } template VTKM_EXEC_CONT ArrayPortalTransform( const ArrayPortalTransform& src) : Superclass(src) , InverseFunctor(src.GetInverseFunctor()) { } template ::type> VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const { this->Portal.Set(index, this->InverseFunctor(value)); } VTKM_EXEC_CONT const InverseFunctorType& GetInverseFunctor() const { return this->InverseFunctor; } private: InverseFunctorType InverseFunctor; }; } } // namespace vtkm::internal namespace vtkm { namespace cont { namespace internal { using NullFunctorType = vtkm::internal::NullFunctorType; template struct TransformFunctorManagerImpl; template struct TransformFunctorManagerImpl { VTKM_STATIC_ASSERT_MSG(!vtkm::cont::internal::IsExecutionObjectBase::value, "Must use an ExecutionAndControlObject instead of an ExecutionObject."); ProvidedFunctorType Functor; using FunctorType = ProvidedFunctorType; TransformFunctorManagerImpl() = default; VTKM_CONT TransformFunctorManagerImpl(const ProvidedFunctorType& functor) : Functor(functor) { } VTKM_CONT ProvidedFunctorType PrepareForControl() const { return this->Functor; } VTKM_CONT ProvidedFunctorType PrepareForExecution(vtkm::cont::DeviceAdapterId, vtkm::cont::Token&) const { return this->Functor; } }; template struct TransformFunctorManagerImpl { VTKM_IS_EXECUTION_AND_CONTROL_OBJECT(ProvidedFunctorType); ProvidedFunctorType Functor; // using FunctorType = decltype(std::declval().PrepareForControl()); // using FunctorType = decltype(Functor.PrepareForControl()); using FunctorType = vtkm::cont::internal::ControlObjectType; TransformFunctorManagerImpl() = default; VTKM_CONT TransformFunctorManagerImpl(const ProvidedFunctorType& functor) : Functor(functor) { } VTKM_CONT auto PrepareForControl() const -> decltype(vtkm::cont::internal::CallPrepareForControl(this->Functor)) { return vtkm::cont::internal::CallPrepareForControl(this->Functor); } VTKM_CONT auto PrepareForExecution(vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) const -> decltype(vtkm::cont::internal::CallPrepareForExecution(this->Functor, device, token)) { return vtkm::cont::internal::CallPrepareForExecution(this->Functor, device, token); } }; template struct TransformFunctorManager : TransformFunctorManagerImpl< ProvidedFunctorType, typename vtkm::cont::internal::IsExecutionAndControlObjectBase::type> { using Superclass = TransformFunctorManagerImpl< ProvidedFunctorType, typename vtkm::cont::internal::IsExecutionAndControlObjectBase::type>; using FunctorType = typename Superclass::FunctorType; VTKM_CONT TransformFunctorManager() = default; VTKM_CONT TransformFunctorManager(const TransformFunctorManager&) = default; VTKM_CONT TransformFunctorManager(const ProvidedFunctorType& functor) : Superclass(functor) { } template using TransformedValueType = decltype(std::declval()(ValueType{})); }; template struct VTKM_ALWAYS_EXPORT StorageTagTransform { using FunctorManager = TransformFunctorManager; using ValueType = typename FunctorManager::template TransformedValueType; }; template class Storage::ValueType, StorageTagTransform> { using FunctorManager = TransformFunctorManager; using ValueType = typename StorageTagTransform::ValueType; using SourceStorage = Storage; static constexpr vtkm::IdComponent NUM_METADATA_BUFFERS = 1; public: VTKM_STORAGE_NO_RESIZE; VTKM_STORAGE_NO_WRITE_PORTAL; using ReadPortalType = vtkm::internal::ArrayPortalTransform; VTKM_CONT static vtkm::IdComponent GetNumberOfBuffers() { return SourceStorage::GetNumberOfBuffers() + NUM_METADATA_BUFFERS; } VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers) { return SourceStorage::GetNumberOfValues(buffers + NUM_METADATA_BUFFERS); } VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers, vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) { if (device == vtkm::cont::DeviceAdapterTagUndefined{}) { return ReadPortalType( SourceStorage::CreateReadPortal(buffers + NUM_METADATA_BUFFERS, device, token), buffers[0].GetMetaData().PrepareForControl()); } else { return ReadPortalType( SourceStorage::CreateReadPortal(buffers + NUM_METADATA_BUFFERS, device, token), buffers[0].GetMetaData().PrepareForExecution(device, token)); } } VTKM_CONT static std::vector CreateBuffers( const ArrayHandleType& handle, const FunctorType& functor = FunctorType()) { return vtkm::cont::internal::CreateBuffers(FunctorManager(functor), handle); } VTKM_CONT static ArrayHandleType GetArray(const vtkm::cont::internal::Buffer* buffers) { return vtkm::cont::ArrayHandle(buffers + NUM_METADATA_BUFFERS); } VTKM_CONT static FunctorType GetFunctor(const vtkm::cont::internal::Buffer* buffers) { return buffers[0].GetMetaData().Functor; } VTKM_CONT static NullFunctorType GetInverseFunctor(const vtkm::cont::internal::Buffer*) { return NullFunctorType{}; } }; template class Storage< typename StorageTagTransform::ValueType, StorageTagTransform> { using FunctorManager = TransformFunctorManager; using InverseFunctorManager = TransformFunctorManager; using ValueType = typename StorageTagTransform::ValueType; using SourceStorage = Storage; static constexpr vtkm::IdComponent NUM_METADATA_BUFFERS = 2; public: using ReadPortalType = vtkm::internal::ArrayPortalTransform; using WritePortalType = vtkm::internal::ArrayPortalTransform; VTKM_CONT constexpr static vtkm::IdComponent GetNumberOfBuffers() { return SourceStorage::GetNumberOfBuffers() + NUM_METADATA_BUFFERS; } VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers) { return SourceStorage::GetNumberOfValues(buffers + NUM_METADATA_BUFFERS); } VTKM_CONT static void ResizeBuffers(vtkm::Id numValues, vtkm::cont::internal::Buffer* buffers, vtkm::CopyFlag preserve, vtkm::cont::Token& token) { SourceStorage::ResizeBuffers(numValues, buffers + NUM_METADATA_BUFFERS, preserve, token); } VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers, vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) { if (device == vtkm::cont::DeviceAdapterTagUndefined{}) { return ReadPortalType( SourceStorage::CreateReadPortal(buffers + NUM_METADATA_BUFFERS, device, token), buffers[0].GetMetaData().PrepareForControl(), buffers[1].GetMetaData().PrepareForControl()); } else { return ReadPortalType( SourceStorage::CreateReadPortal(buffers + NUM_METADATA_BUFFERS, device, token), buffers[0].GetMetaData().PrepareForExecution(device, token), buffers[1].GetMetaData().PrepareForExecution(device, token)); } } VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers, vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) { return WritePortalType( SourceStorage::CreateWritePortal(buffers + NUM_METADATA_BUFFERS, device, token), buffers[0].GetMetaData().PrepareForExecution(device, token), buffers[1].GetMetaData().PrepareForExecution(device, token)); } VTKM_CONT static std::vector CreateBuffers( const ArrayHandleType& handle, const FunctorType& functor = FunctorType(), const InverseFunctorType& inverseFunctor = InverseFunctorType()) { return vtkm::cont::internal::CreateBuffers( FunctorManager(functor), InverseFunctorManager(inverseFunctor), handle); } VTKM_CONT static ArrayHandleType GetArray(const vtkm::cont::internal::Buffer* buffers) { return vtkm::cont::ArrayHandle(buffers + NUM_METADATA_BUFFERS); } VTKM_CONT static FunctorType GetFunctor(const vtkm::cont::internal::Buffer* buffers) { return buffers[0].GetMetaData().Functor; } VTKM_CONT static InverseFunctorType GetInverseFunctor(const vtkm::cont::internal::Buffer* buffers) { return buffers[1].GetMetaData().Functor; } }; } // namespace internal /// \brief Implicitly transform values of one array to another with a functor. /// /// ArrayHandleTransforms is a specialization of ArrayHandle. It takes a /// delegate array handle and makes a new handle that calls a given unary /// functor with the element at a given index and returns the result of the /// functor as the value of this array at that position. This transformation is /// done on demand. That is, rather than make a new copy of the array with new /// values, the transformation is done as values are read from the array. Thus, /// the functor operator should work in both the control and execution /// environments. /// template class ArrayHandleTransform; template class ArrayHandleTransform : public vtkm::cont::ArrayHandle< typename internal::StorageTagTransform::ValueType, internal::StorageTagTransform> { // If the following line gives a compile error, then the ArrayHandleType // template argument is not a valid ArrayHandle type. VTKM_IS_ARRAY_HANDLE(ArrayHandleType); public: VTKM_ARRAY_HANDLE_SUBCLASS( ArrayHandleTransform, (ArrayHandleTransform), (vtkm::cont::ArrayHandle< typename internal::StorageTagTransform::ValueType, internal::StorageTagTransform>)); private: using StorageType = vtkm::cont::internal::Storage; public: VTKM_CONT ArrayHandleTransform(const ArrayHandleType& handle, const FunctorType& functor = FunctorType{}, internal::NullFunctorType = internal::NullFunctorType{}) : Superclass(StorageType::CreateBuffers(handle, functor)) { } }; /// make_ArrayHandleTransform is convenience function to generate an /// ArrayHandleTransform. It takes in an ArrayHandle and a functor /// to apply to each element of the Handle. template VTKM_CONT vtkm::cont::ArrayHandleTransform make_ArrayHandleTransform( HandleType handle, FunctorType functor) { return ArrayHandleTransform(handle, functor); } // ArrayHandleTransform with inverse functors enabled (no need to subclass from // ArrayHandleTransform without inverse functors: nothing to inherit). template class ArrayHandleTransform : public vtkm::cont::ArrayHandle< typename internal::StorageTagTransform:: ValueType, internal::StorageTagTransform> { VTKM_IS_ARRAY_HANDLE(ArrayHandleType); public: VTKM_ARRAY_HANDLE_SUBCLASS( ArrayHandleTransform, (ArrayHandleTransform), (vtkm::cont::ArrayHandle< typename internal::StorageTagTransform:: ValueType, internal::StorageTagTransform>)); private: using StorageType = vtkm::cont::internal::Storage; public: ArrayHandleTransform(const ArrayHandleType& handle, const FunctorType& functor = FunctorType(), const InverseFunctorType& inverseFunctor = InverseFunctorType()) : Superclass(StorageType::CreateBuffers(handle, functor, inverseFunctor)) { } /// Implemented so that it is defined exclusively in the control environment. /// If there is a separate device for the execution environment (for example, /// with CUDA), then the automatically generated destructor could be /// created for all devices, and it would not be valid for all devices. /// ~ArrayHandleTransform() {} /// \brief Returns the `ArrayHandle` that is being transformed. /// ArrayHandleType GetTransformedArray() const { return StorageType::GetArray(this->GetBuffers()); } /// \brief Returns the functor transforming the `ArrayHandle`. /// FunctorType GetFunctor() const { return StorageType::GetFunctor(this->GetBuffers()); } /// \brief Returns the inverse functor transforming the `ArrayHandle` /// InverseFunctorType GetInverseFunctor() const { return StorageType::GetInverseFunctor(this->GetBuffers()); } }; template VTKM_CONT vtkm::cont::ArrayHandleTransform make_ArrayHandleTransform(HandleType handle, FunctorType functor, InverseFunctorType inverseFunctor) { return ArrayHandleTransform( handle, functor, inverseFunctor); } } } // namespace vtkm::cont //============================================================================= // Specializations of serialization related classes /// @cond SERIALIZATION namespace vtkm { namespace cont { template struct SerializableTypeString> { static VTKM_CONT const std::string& Get() { static std::string name = "AH_Transform<" + SerializableTypeString::Get() + "," + SerializableTypeString::Get() + "," + SerializableTypeString::Get() + ">"; return name; } }; template struct SerializableTypeString> { static VTKM_CONT const std::string& Get() { static std::string name = "AH_Transform<" + SerializableTypeString::Get() + "," + SerializableTypeString::Get() + ">"; return name; } }; template struct SerializableTypeString::ValueType, vtkm::cont::internal::StorageTagTransform>> : SerializableTypeString> { }; } } // vtkm::cont namespace mangled_diy_namespace { template struct Serialization> { private: using Type = vtkm::cont::ArrayHandleTransform; using BaseType = vtkm::cont::ArrayHandle; public: static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj) { Type transformedArray = obj; vtkmdiy::save(bb, obj.GetArray()); vtkmdiy::save(bb, obj.GetFunctor()); } static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj) { AH array; vtkmdiy::load(bb, array); Functor functor; vtkmdiy::load(bb, functor); obj = vtkm::cont::make_ArrayHandleTransform(array, functor); } }; template struct Serialization> { private: using Type = vtkm::cont::ArrayHandleTransform; using BaseType = vtkm::cont::ArrayHandle; public: static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj) { Type transformedArray = obj; vtkmdiy::save(bb, transformedArray.GetTransformedArray()); vtkmdiy::save(bb, transformedArray.GetFunctor()); vtkmdiy::save(bb, transformedArray.GetInverseFunctor()); } static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj) { AH array; vtkmdiy::load(bb, array); Functor functor; vtkmdiy::load(bb, functor); InvFunctor invFunctor; vtkmdiy::load(bb, invFunctor); obj = vtkm::cont::make_ArrayHandleTransform(array, functor, invFunctor); } }; template struct Serialization::ValueType, vtkm::cont::internal::StorageTagTransform>> : Serialization> { }; } // diy /// @endcond SERIALIZATION #endif //vtk_m_cont_ArrayHandleTransform_h