//============================================================================ // 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_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 { using ReadableP1 = vtkm::internal::PortalSupportsGets; using ReadableP2 = vtkm::internal::PortalSupportsGets; using WritableP1 = vtkm::internal::PortalSupportsSets; using WritableP2 = vtkm::internal::PortalSupportsSets; using Readable = std::integral_constant; using Writable = std::integral_constant; public: using T = typename PortalTypeFirst::ValueType; using U = typename PortalTypeSecond::ValueType; using ValueType = vtkm::Pair; 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_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const { return this->PortalFirst.GetNumberOfValues(); } VTKM_SUPPRESS_EXEC_WARNINGS template ::type> VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const noexcept { return vtkm::make_Pair(this->PortalFirst.Get(index), this->PortalSecond.Get(index)); } VTKM_SUPPRESS_EXEC_WARNINGS template ::type> VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const noexcept { this->PortalFirst.Set(index, value.first); this->PortalSecond.Set(index, value.second); } VTKM_EXEC_CONT const PortalTypeFirst& GetFirstPortal() const { return this->PortalFirst; } VTKM_EXEC_CONT const PortalTypeSecond& GetSecondPortal() const { return this->PortalSecond; } private: PortalTypeFirst PortalFirst; PortalTypeSecond PortalSecond; }; } } } // namespace vtkm::exec::internal namespace vtkm { namespace cont { template struct VTKM_ALWAYS_EXPORT StorageTagZip { }; namespace internal { /// 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 storage type. /// using Storage = vtkm::cont::internal::Storage; /// The superclass for ArrayHandleZip. /// using Superclass = vtkm::cont::ArrayHandle; }; template class Storage, vtkm::cont::StorageTagZip> { using FirstStorage = Storage; using SecondStorage = Storage; using ValueType = vtkm::Pair; using FirstArrayType = vtkm::cont::ArrayHandle; using SecondArrayType = vtkm::cont::ArrayHandle; struct Info { std::size_t SecondBuffersOffset; }; VTKM_CONT static std::vector FirstArrayBuffers( const std::vector& buffers) { const Info& info = buffers[0].GetMetaData(); return std::vector(buffers.begin() + 1, buffers.begin() + info.SecondBuffersOffset); } VTKM_CONT static std::vector SecondArrayBuffers( const std::vector& buffers) { const Info& info = buffers[0].GetMetaData(); return std::vector(buffers.begin() + info.SecondBuffersOffset, buffers.end()); } public: using ReadPortalType = vtkm::exec::internal::ArrayPortalZip; using WritePortalType = vtkm::exec::internal::ArrayPortalZip; static std::vector CreateBuffers( const FirstArrayType& firstArray = FirstArrayType{}, const SecondArrayType& secondArray = SecondArrayType{}) { Info info; info.SecondBuffersOffset = 1 + firstArray.GetBuffers().size(); return vtkm::cont::internal::CreateBuffers(info, firstArray, secondArray); } VTKM_CONT static void ResizeBuffers(vtkm::Id numValues, const std::vector& buffers, vtkm::CopyFlag preserve, vtkm::cont::Token& token) { FirstStorage::ResizeBuffers(numValues, FirstArrayBuffers(buffers), preserve, token); SecondStorage::ResizeBuffers(numValues, SecondArrayBuffers(buffers), preserve, token); } VTKM_CONT static vtkm::Id GetNumberOfValues( const std::vector& buffers) { vtkm::Id numValues = FirstStorage::GetNumberOfValues(FirstArrayBuffers(buffers)); VTKM_ASSERT(numValues == SecondStorage::GetNumberOfValues(SecondArrayBuffers(buffers))); return numValues; } VTKM_CONT static void Fill(const std::vector& buffers, const ValueType& fillValue, vtkm::Id startIndex, vtkm::Id endIndex, vtkm::cont::Token& token) { FirstStorage::Fill(FirstArrayBuffers(buffers), fillValue.first, startIndex, endIndex, token); SecondStorage::Fill(SecondArrayBuffers(buffers), fillValue.second, startIndex, endIndex, token); } VTKM_CONT static ReadPortalType CreateReadPortal( const std::vector& buffers, vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) { return ReadPortalType( FirstStorage::CreateReadPortal(FirstArrayBuffers(buffers), device, token), SecondStorage::CreateReadPortal(SecondArrayBuffers(buffers), device, token)); } VTKM_CONT static WritePortalType CreateWritePortal( const std::vector& buffers, vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) { return WritePortalType( FirstStorage::CreateWritePortal(FirstArrayBuffers(buffers), device, token), SecondStorage::CreateWritePortal(SecondArrayBuffers(buffers), device, token)); } static FirstArrayType GetFirstArray(const std::vector& buffers) { return { FirstArrayBuffers(buffers) }; } static SecondArrayType GetSecondArray(const std::vector& buffers) { return { SecondArrayBuffers(buffers) }; } }; } // 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); using StorageType = typename internal::ArrayHandleZipTraits::Storage; public: VTKM_ARRAY_HANDLE_SUBCLASS( ArrayHandleZip, (ArrayHandleZip), (typename internal::ArrayHandleZipTraits::Superclass)); VTKM_CONT ArrayHandleZip(const FirstHandleType& firstArray, const SecondHandleType& secondArray) : Superclass(StorageType::CreateBuffers(firstArray, secondArray)) { } FirstHandleType GetFirstArray() const { return StorageType::GetFirstArray(this->GetBuffers()); } SecondHandleType GetSecondArray() const { return StorageType::GetSecondArray(this->GetBuffers()); } }; /// 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 /// @cond SERIALIZATION 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::StorageTagZip>> : SerializableTypeString, vtkm::cont::ArrayHandle>> { }; } } // 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::StorageTagZip>> : Serialization, vtkm::cont::ArrayHandle>> { }; } // diy /// @endcond SERIALIZATION #endif //vtk_m_cont_ArrayHandleZip_h