//============================================================================ // 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. // // Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS). // Copyright 2014 UT-Battelle, LLC. // Copyright 2014 Los Alamos National Security. // // Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National // Laboratory (LANL), the U.S. Government retains certain rights in // this software. //============================================================================ #ifndef vtk_m_cont_ArrayHandleZip_h #define vtk_m_cont_ArrayHandleZip_h #include #include #include namespace vtkm { namespace exec { namespace internal { /// \brief An array portal that zips two portals together into a single value /// for the execution environment template class ArrayPortalZip { public: using ValueType = ValueType_; using T = typename ValueType::FirstType; using U = typename ValueType::SecondType; using IteratorType = ValueType_; using PortalTypeFirst = PortalTypeFirst_; using PortalTypeSecond = PortalTypeSecond_; VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT ArrayPortalZip() : PortalFirst() , PortalSecond() { } //needs to be host and device so that cuda can create lvalue of these VTKM_CONT ArrayPortalZip(const PortalTypeFirst& portalfirst, const PortalTypeSecond& portalsecond) : PortalFirst(portalfirst) , PortalSecond(portalsecond) { } /// Copy constructor for any other ArrayPortalZip 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_CONT ArrayPortalZip(const ArrayPortalZip& src) : PortalFirst(src.GetFirstPortal()) , PortalSecond(src.GetSecondPortal()) { } VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const { return this->PortalFirst.GetNumberOfValues(); } VTKM_EXEC ValueType Get(vtkm::Id index) const { using call_supported_t1 = typename vtkm::internal::PortalSupportsGets::type; using call_supported_t2 = typename vtkm::internal::PortalSupportsGets::type; return vtkm::make_Pair(this->GetFirst(call_supported_t1(), index), this->GetSecond(call_supported_t2(), index)); } VTKM_EXEC void Set(vtkm::Id index, const ValueType& value) const { using call_supported_t1 = typename vtkm::internal::PortalSupportsSets::type; using call_supported_t2 = typename vtkm::internal::PortalSupportsSets::type; this->SetFirst(call_supported_t1(), index, value.first); this->SetSecond(call_supported_t2(), index, value.second); } VTKM_EXEC_CONT const PortalTypeFirst& GetFirstPortal() const { return this->PortalFirst; } VTKM_EXEC_CONT const PortalTypeSecond& GetSecondPortal() const { return this->PortalSecond; } private: VTKM_EXEC inline T GetFirst(std::true_type, vtkm::Id index) const noexcept { return this->PortalFirst.Get(index); } VTKM_EXEC inline T GetFirst(std::false_type, vtkm::Id) const noexcept { return T{}; } VTKM_EXEC inline U GetSecond(std::true_type, vtkm::Id index) const noexcept { return this->PortalSecond.Get(index); } VTKM_EXEC inline U GetSecond(std::false_type, vtkm::Id) const noexcept { return U{}; } VTKM_EXEC inline void SetFirst(std::true_type, vtkm::Id index, const T& value) const noexcept { this->PortalFirst.Set(index, value); } VTKM_EXEC inline void SetFirst(std::false_type, vtkm::Id, const T&) const noexcept {} VTKM_EXEC inline void SetSecond(std::true_type, vtkm::Id index, const U& value) const noexcept { this->PortalSecond.Set(index, value); } VTKM_EXEC inline void SetSecond(std::false_type, vtkm::Id, const U&) const noexcept {} PortalTypeFirst PortalFirst; PortalTypeSecond PortalSecond; }; } } } // namespace vtkm::exec::internal namespace vtkm { namespace cont { namespace internal { template struct VTKM_ALWAYS_EXPORT StorageTagZip { }; /// This helper struct defines the value type for a zip container containing /// the given two array handles. /// template struct ArrayHandleZipTraits { /// The ValueType (a pair containing the value types of the two arrays). /// using ValueType = vtkm::Pair; /// The appropriately templated tag. /// using Tag = StorageTagZip; /// The superclass for ArrayHandleZip. /// using Superclass = vtkm::cont::ArrayHandle; }; template class Storage, StorageTagZip> { VTKM_IS_ARRAY_HANDLE(FirstHandleType); VTKM_IS_ARRAY_HANDLE(SecondHandleType); public: using ValueType = vtkm::Pair; using PortalType = vtkm::exec::internal::ArrayPortalZip; using PortalConstType = vtkm::exec::internal::ArrayPortalZip; VTKM_CONT Storage() : FirstArray() , SecondArray() { } VTKM_CONT Storage(const FirstHandleType& farray, const SecondHandleType& sarray) : FirstArray(farray) , SecondArray(sarray) { } VTKM_CONT PortalType GetPortal() { return PortalType(this->FirstArray.GetPortalControl(), this->SecondArray.GetPortalControl()); } VTKM_CONT PortalConstType GetPortalConst() const { return PortalConstType(this->FirstArray.GetPortalConstControl(), this->SecondArray.GetPortalConstControl()); } VTKM_CONT vtkm::Id GetNumberOfValues() const { VTKM_ASSERT(this->FirstArray.GetNumberOfValues() == this->SecondArray.GetNumberOfValues()); return this->FirstArray.GetNumberOfValues(); } VTKM_CONT void Allocate(vtkm::Id numberOfValues) { this->FirstArray.Allocate(numberOfValues); this->SecondArray.Allocate(numberOfValues); } VTKM_CONT void Shrink(vtkm::Id numberOfValues) { this->FirstArray.Shrink(numberOfValues); this->SecondArray.Shrink(numberOfValues); } VTKM_CONT void ReleaseResources() { // This request is ignored since it is asking to release the resources // of the two zipped array, which may be used elsewhere. } VTKM_CONT const FirstHandleType& GetFirstArray() const { return this->FirstArray; } VTKM_CONT const SecondHandleType& GetSecondArray() const { return this->SecondArray; } private: FirstHandleType FirstArray; SecondHandleType SecondArray; }; template class ArrayTransfer< vtkm::Pair, StorageTagZip, Device> { public: using ValueType = vtkm::Pair; private: using StorageTag = StorageTagZip; using StorageType = vtkm::cont::internal::Storage; public: using PortalControl = typename StorageType::PortalType; using PortalConstControl = typename StorageType::PortalConstType; using PortalExecution = vtkm::exec::internal::ArrayPortalZip< ValueType, typename FirstHandleType::template ExecutionTypes::Portal, typename SecondHandleType::template ExecutionTypes::Portal>; using PortalConstExecution = vtkm::exec::internal::ArrayPortalZip< ValueType, typename FirstHandleType::template ExecutionTypes::PortalConst, typename SecondHandleType::template ExecutionTypes::PortalConst>; VTKM_CONT ArrayTransfer(StorageType* storage) : FirstArray(storage->GetFirstArray()) , SecondArray(storage->GetSecondArray()) { } VTKM_CONT vtkm::Id GetNumberOfValues() const { VTKM_ASSERT(this->FirstArray.GetNumberOfValues() == this->SecondArray.GetNumberOfValues()); return this->FirstArray.GetNumberOfValues(); } VTKM_CONT PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData)) { return PortalConstExecution(this->FirstArray.PrepareForInput(Device()), this->SecondArray.PrepareForInput(Device())); } VTKM_CONT PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData)) { return PortalExecution(this->FirstArray.PrepareForInPlace(Device()), this->SecondArray.PrepareForInPlace(Device())); } VTKM_CONT PortalExecution PrepareForOutput(vtkm::Id numberOfValues) { return PortalExecution(this->FirstArray.PrepareForOutput(numberOfValues, Device()), this->SecondArray.PrepareForOutput(numberOfValues, Device())); } VTKM_CONT void RetrieveOutputData(StorageType* vtkmNotUsed(storage)) const { // Implementation of this method should be unnecessary. The internal // first and second array handles should automatically retrieve the // output data as necessary. } VTKM_CONT void Shrink(vtkm::Id numberOfValues) { this->FirstArray.Shrink(numberOfValues); this->SecondArray.Shrink(numberOfValues); } VTKM_CONT void ReleaseResources() { this->FirstArray.ReleaseResourcesExecution(); this->SecondArray.ReleaseResourcesExecution(); } private: FirstHandleType FirstArray; SecondHandleType SecondArray; }; } // namespace internal /// ArrayHandleZip is a specialization of ArrayHandle. It takes two delegate /// array handle and makes a new handle that access the corresponding entries /// in these arrays as a pair. /// template class ArrayHandleZip : public internal::ArrayHandleZipTraits::Superclass { // If the following line gives a compile error, then the FirstHandleType // template argument is not a valid ArrayHandle type. VTKM_IS_ARRAY_HANDLE(FirstHandleType); // If the following line gives a compile error, then the SecondHandleType // template argument is not a valid ArrayHandle type. VTKM_IS_ARRAY_HANDLE(SecondHandleType); public: VTKM_ARRAY_HANDLE_SUBCLASS( ArrayHandleZip, (ArrayHandleZip), (typename internal::ArrayHandleZipTraits::Superclass)); private: using StorageType = vtkm::cont::internal::Storage; public: VTKM_CONT ArrayHandleZip(const FirstHandleType& firstArray, const SecondHandleType& secondArray) : Superclass(StorageType(firstArray, secondArray)) { } }; /// A convenience function for creating an ArrayHandleZip. It takes the two /// arrays to be zipped together. /// template VTKM_CONT vtkm::cont::ArrayHandleZip make_ArrayHandleZip( const FirstHandleType& first, const SecondHandleType& second) { return ArrayHandleZip(first, second); } } } // 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_Zip<" + SerializableTypeString::Get() + "," + SerializableTypeString::Get() + ">"; return name; } }; template struct SerializableTypeString< vtkm::cont::ArrayHandle, vtkm::cont::internal::StorageTagZip>> : SerializableTypeString> { }; } } // namespace vtkm::cont namespace mangled_diy_namespace { template struct Serialization> { private: using Type = typename vtkm::cont::ArrayHandleZip; using BaseType = vtkm::cont::ArrayHandle; public: static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj) { auto storage = obj.GetStorage(); vtkmdiy::save(bb, storage.GetFirstArray()); vtkmdiy::save(bb, storage.GetSecondArray()); } static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj) { AH1 a1; AH2 a2; vtkmdiy::load(bb, a1); vtkmdiy::load(bb, a2); obj = vtkm::cont::make_ArrayHandleZip(a1, a2); } }; template struct Serialization< vtkm::cont::ArrayHandle, vtkm::cont::internal::StorageTagZip>> : Serialization> { }; } // diy #endif //vtk_m_cont_ArrayHandleZip_h