//============================================================================ // 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 namespace vtkm { namespace cont { namespace internal { /// Tag used in place of an inverse functor. struct NullFunctorType { }; } } } // namespace vtkm::cont::internal namespace vtkm { namespace exec { namespace internal { using NullFunctorType = vtkm::cont::internal::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_SUPPRESS_EXEC_WARNINGS 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). /// VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT ArrayPortalTransform(const ArrayPortalTransform& src) : Portal(src.GetPortal()) , Functor(src.GetFunctor()) { } VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const { return this->Portal.GetNumberOfValues(); } VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const { return this->Functor(this->Portal.Get(index)); } VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT void Set(vtkm::Id vtkmNotUsed(index), const ValueType& vtkmNotUsed(value)) const { #if !(defined(VTKM_MSVC) && defined(VTKM_CUDA)) VTKM_ASSERT(false && "Cannot write to read-only transform array. (No inverse transform given.)"); #endif } VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT const PortalType& GetPortal() const { return this->Portal; } VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT const FunctorType& GetFunctor() const { return this->Functor; } protected: PortalType Portal; FunctorType Functor; }; template class VTKM_ALWAYS_EXPORT ArrayPortalTransform : public ArrayPortalTransform { public: using Superclass = ArrayPortalTransform; using PortalType = PortalType_; using ValueType = ValueType_; using FunctorType = FunctorType_; using InverseFunctorType = InverseFunctorType_; VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT ArrayPortalTransform(const PortalType& portal = PortalType(), const FunctorType& functor = FunctorType(), const InverseFunctorType& inverseFunctor = InverseFunctorType()) : Superclass(portal, functor) , InverseFunctor(inverseFunctor) { } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT ArrayPortalTransform( const ArrayPortalTransform& src) : Superclass(src) , InverseFunctor(src.GetInverseFunctor()) { } VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const { return this->Portal.Set(index, this->InverseFunctor(value)); } VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT const InverseFunctorType& GetInverseFunctor() const { return this->InverseFunctor; } private: InverseFunctorType InverseFunctor; }; } } } // namespace vtkm::exec::internal namespace vtkm { namespace cont { namespace internal { 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; } template VTKM_CONT ProvidedFunctorType PrepareForExecution(Device) 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()); TransformFunctorManagerImpl() = default; VTKM_CONT TransformFunctorManagerImpl(const ProvidedFunctorType& functor) : Functor(functor) { } VTKM_CONT auto PrepareForControl() const -> decltype(this->Functor.PrepareForControl()) { return this->Functor.PrepareForControl(); } template VTKM_CONT auto PrepareForExecution(Device device) const -> decltype(this->Functor.PrepareForExecution(device)) { return this->Functor.PrepareForExecution(device); } }; 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& other) = 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; public: using ValueType = typename StorageTagTransform::ValueType; // This is meant to be invalid. Because Transform arrays are read only, you // should only be able to use the const version. struct PortalType { using ValueType = void*; using IteratorType = void*; }; using PortalConstType = vtkm::exec::internal::ArrayPortalTransform; VTKM_CONT Storage() : Valid(false) { } VTKM_CONT Storage(const ArrayHandleType& array, const FunctorType& functor = FunctorType()) : Array(array) , Functor(functor) , Valid(true) { } VTKM_CONT PortalType GetPortal() { throw vtkm::cont::ErrorBadType( "ArrayHandleTransform is read only. Cannot get writable portal."); } VTKM_CONT PortalConstType GetPortalConst() const { VTKM_ASSERT(this->Valid); vtkm::cont::ScopedRuntimeDeviceTracker trackerScope; vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagSerial()); return PortalConstType(this->Array.GetPortalConstControl(), this->Functor.PrepareForControl()); } VTKM_CONT vtkm::Id GetNumberOfValues() const { VTKM_ASSERT(this->Valid); return this->Array.GetNumberOfValues(); } VTKM_CONT void Allocate(vtkm::Id vtkmNotUsed(numberOfValues)) { throw vtkm::cont::ErrorBadType("ArrayHandleTransform is read only. It cannot be allocated."); } VTKM_CONT void Shrink(vtkm::Id vtkmNotUsed(numberOfValues)) { throw vtkm::cont::ErrorBadType("ArrayHandleTransform is read only. It cannot shrink."); } VTKM_CONT void ReleaseResources() { // This request is ignored since it is asking to release the resources // of the delegate array, which may be used elsewhere. Should the behavior // be different? } VTKM_CONT const ArrayHandleType& GetArray() const { VTKM_ASSERT(this->Valid); return this->Array; } VTKM_CONT const FunctorManager& GetFunctor() const { return this->Functor; } private: ArrayHandleType Array; FunctorManager Functor; bool Valid; }; template class Storage< typename StorageTagTransform::ValueType, StorageTagTransform> { using FunctorManager = TransformFunctorManager; using InverseFunctorManager = TransformFunctorManager; public: using ValueType = typename StorageTagTransform::ValueType; using PortalType = vtkm::exec::internal::ArrayPortalTransform; using PortalConstType = vtkm::exec::internal::ArrayPortalTransform; VTKM_CONT Storage() : Valid(false) { } VTKM_CONT Storage(const ArrayHandleType& array, const FunctorType& functor, const InverseFunctorType& inverseFunctor) : Array(array) , Functor(functor) , InverseFunctor(inverseFunctor) , Valid(true) { } VTKM_CONT PortalType GetPortal() { VTKM_ASSERT(this->Valid); vtkm::cont::ScopedRuntimeDeviceTracker trackerScope; vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagSerial()); return PortalType(this->Array.GetPortalControl(), this->Functor.PrepareForControl(), this->InverseFunctor.PrepareForControl()); } VTKM_CONT PortalConstType GetPortalConst() const { VTKM_ASSERT(this->Valid); vtkm::cont::ScopedRuntimeDeviceTracker trackerScope; vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagSerial()); return PortalConstType(this->Array.GetPortalConstControl(), this->Functor.PrepareForControl(), this->InverseFunctor.PrepareForControl()); } VTKM_CONT vtkm::Id GetNumberOfValues() const { VTKM_ASSERT(this->Valid); return this->Array.GetNumberOfValues(); } VTKM_CONT void Allocate(vtkm::Id numberOfValues) { this->Array.Allocate(numberOfValues); this->Valid = true; } VTKM_CONT void Shrink(vtkm::Id numberOfValues) { this->Array.Shrink(numberOfValues); } VTKM_CONT void ReleaseResources() { this->Array.ReleaseResources(); this->Valid = false; } VTKM_CONT const ArrayHandleType& GetArray() const { VTKM_ASSERT(this->Valid); return this->Array; } VTKM_CONT const FunctorManager& GetFunctor() const { return this->Functor; } VTKM_CONT const InverseFunctorManager& GetInverseFunctor() const { return this->InverseFunctor; } private: ArrayHandleType Array; FunctorManager Functor; InverseFunctorManager InverseFunctor; bool Valid; }; template class ArrayTransfer::ValueType, StorageTagTransform, Device> { using StorageTag = StorageTagTransform; using FunctorManager = TransformFunctorManager; public: using ValueType = typename StorageTagTransform::ValueType; using StorageType = vtkm::cont::internal::Storage; using PortalControl = typename StorageType::PortalType; using PortalConstControl = typename StorageType::PortalConstType; //meant to be an invalid writeable execution portal using PortalExecution = typename StorageType::PortalType; using PortalConstExecution = vtkm::exec::internal::ArrayPortalTransform< ValueType, typename ArrayHandleType::template ExecutionTypes::PortalConst, typename FunctorManager::FunctorType>; VTKM_CONT ArrayTransfer(StorageType* storage) : Array(storage->GetArray()) , Functor(storage->GetFunctor()) { } VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->Array.GetNumberOfValues(); } VTKM_CONT PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData)) { return PortalConstExecution(this->Array.PrepareForInput(Device()), this->Functor.PrepareForExecution(Device())); } VTKM_CONT PortalExecution PrepareForInPlace(bool& vtkmNotUsed(updateData)) { throw vtkm::cont::ErrorBadType("ArrayHandleTransform read only. " "Cannot be used for in-place operations."); } VTKM_CONT PortalExecution PrepareForOutput(vtkm::Id vtkmNotUsed(numberOfValues)) { throw vtkm::cont::ErrorBadType("ArrayHandleTransform read only. Cannot be used as output."); } VTKM_CONT void RetrieveOutputData(StorageType* vtkmNotUsed(storage)) const { throw vtkm::cont::ErrorInternal( "ArrayHandleTransform read only. " "There should be no occurrence of the ArrayHandle trying to pull " "data from the execution environment."); } VTKM_CONT void Shrink(vtkm::Id vtkmNotUsed(numberOfValues)) { throw vtkm::cont::ErrorBadType("ArrayHandleTransform read only. Cannot shrink."); } VTKM_CONT void ReleaseResources() { this->Array.ReleaseResourcesExecution(); } private: ArrayHandleType Array; FunctorManager Functor; }; template class ArrayTransfer< typename StorageTagTransform::ValueType, StorageTagTransform, Device> { using StorageTag = StorageTagTransform; using FunctorManager = TransformFunctorManager; using InverseFunctorManager = TransformFunctorManager; public: using ValueType = typename StorageTagTransform::ValueType; using StorageType = vtkm::cont::internal::Storage; using PortalControl = typename StorageType::PortalType; using PortalConstControl = typename StorageType::PortalConstType; using PortalExecution = vtkm::exec::internal::ArrayPortalTransform< ValueType, typename ArrayHandleType::template ExecutionTypes::Portal, typename FunctorManager::FunctorType, typename InverseFunctorManager::FunctorType>; using PortalConstExecution = vtkm::exec::internal::ArrayPortalTransform< ValueType, typename ArrayHandleType::template ExecutionTypes::PortalConst, typename FunctorManager::FunctorType, typename InverseFunctorManager::FunctorType>; VTKM_CONT ArrayTransfer(StorageType* storage) : Array(storage->GetArray()) , Functor(storage->GetFunctor()) , InverseFunctor(storage->GetInverseFunctor()) { } VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->Array.GetNumberOfValues(); } VTKM_CONT PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData)) { return PortalConstExecution(this->Array.PrepareForInput(Device()), this->Functor.PrepareForExecution(Device()), this->InverseFunctor.PrepareForExecution(Device())); } VTKM_CONT PortalExecution PrepareForInPlace(bool& vtkmNotUsed(updateData)) { return PortalExecution(this->Array.PrepareForInPlace(Device()), this->Functor.PrepareForExecution(Device()), this->InverseFunctor.PrepareForExecution(Device())); } VTKM_CONT PortalExecution PrepareForOutput(vtkm::Id numberOfValues) { return PortalExecution(this->Array.PrepareForOutput(numberOfValues, Device()), this->Functor.PrepareForExecution(Device()), this->InverseFunctor.PrepareForExecution(Device())); } VTKM_CONT void RetrieveOutputData(StorageType* vtkmNotUsed(storage)) const { // Implementation of this method should be unnecessary. The internal // array handle should automatically retrieve the output data as necessary. } VTKM_CONT void Shrink(vtkm::Id numberOfValues) { this->Array.Shrink(numberOfValues); } VTKM_CONT void ReleaseResources() { this->Array.ReleaseResourcesExecution(); } private: ArrayHandleType Array; FunctorManager Functor; InverseFunctorManager InverseFunctor; }; } // 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()) : Superclass(StorageType(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(handle, functor, inverseFunctor)) { } }; 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 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) { auto storage = obj.GetStorage(); vtkmdiy::save(bb, storage.GetArray()); vtkmdiy::save(bb, storage.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) { auto storage = obj.GetStorage(); vtkmdiy::save(bb, storage.GetArray()); vtkmdiy::save(bb, storage.GetFunctor()); vtkmdiy::save(bb, storage.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 #endif //vtk_m_cont_ArrayHandleTransform_h