//============================================================================ // 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_ArrayHandleGroupVec_h #define vtk_m_cont_ArrayHandleGroupVec_h #include #include #include #include namespace vtkm { namespace internal { template class VTKM_ALWAYS_EXPORT ArrayPortalGroupVec { using Writable = vtkm::internal::PortalSupportsSets; public: static constexpr vtkm::IdComponent NUM_COMPONENTS = N_COMPONENTS; using ComponentsPortalType = PortalType; using ComponentType = typename std::remove_const::type; using ValueType = vtkm::Vec; VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT ArrayPortalGroupVec() : ComponentsPortal() { } VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT ArrayPortalGroupVec(const ComponentsPortalType& componentsPortal) : ComponentsPortal(componentsPortal) { } /// Copy constructor for any other ArrayPortalConcatenate with a portal type /// that can be copied to this portal type. This allows us to do any type /// casting that the portals do (like the non-const to const cast). VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT ArrayPortalGroupVec( const ArrayPortalGroupVec& src) : ComponentsPortal(src.GetPortal()) { } VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const { return this->ComponentsPortal.GetNumberOfValues() / NUM_COMPONENTS; } VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const { ValueType result; vtkm::Id componentsIndex = index * NUM_COMPONENTS; for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) { result[componentIndex] = this->ComponentsPortal.Get(componentsIndex); componentsIndex++; } return result; } VTKM_SUPPRESS_EXEC_WARNINGS template ::type> VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const { vtkm::Id componentsIndex = index * NUM_COMPONENTS; for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) { this->ComponentsPortal.Set(componentsIndex, value[componentIndex]); componentsIndex++; } } VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT const ComponentsPortalType& GetPortal() const { return this->ComponentsPortal; } private: ComponentsPortalType ComponentsPortal; }; } } // namespace vtkm::internal namespace vtkm { namespace cont { template struct VTKM_ALWAYS_EXPORT StorageTagGroupVec { }; namespace internal { template class Storage, vtkm::cont::StorageTagGroupVec> { using ComponentsStorage = vtkm::cont::internal::Storage; using ValueType = vtkm::Vec; public: using ReadPortalType = vtkm::internal::ArrayPortalGroupVec; using WritePortalType = vtkm::internal::ArrayPortalGroupVec; VTKM_CONT constexpr static vtkm::IdComponent GetNumberOfBuffers() { return ComponentsStorage::GetNumberOfBuffers(); } VTKM_CONT static void ResizeBuffers(vtkm::Id numValues, vtkm::cont::internal::Buffer* buffers, vtkm::CopyFlag preserve, vtkm::cont::Token& token) { ComponentsStorage::ResizeBuffers(NUM_COMPONENTS * numValues, buffers, preserve, token); } VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers) { vtkm::Id componentsSize = ComponentsStorage::GetNumberOfValues(buffers); return componentsSize / NUM_COMPONENTS; } VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers, vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) { if ((ComponentsStorage::GetNumberOfValues(buffers) % NUM_COMPONENTS) != 0) { VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "ArrayHandleGroupVec's components array does not divide evenly into Vecs."); } return ReadPortalType(ComponentsStorage::CreateReadPortal(buffers, device, token)); } VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers, vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) { if ((ComponentsStorage::GetNumberOfValues(buffers) % NUM_COMPONENTS) != 0) { VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "ArrayHandleGroupVec's components array does not divide evenly into Vecs."); } return WritePortalType(ComponentsStorage::CreateWritePortal(buffers, device, token)); } }; } // namespace internal /// \brief Fancy array handle that groups values into vectors. /// /// It is sometimes the case that an array is stored such that consecutive /// entries are meant to form a group. This fancy array handle takes an array /// of values and a size of groups and then groups the consecutive values /// stored in a \c Vec. /// /// For example, if you have an array handle with the six values 0,1,2,3,4,5 /// and give it to a \c ArrayHandleGroupVec with the number of components set /// to 3, you get an array that looks like it contains two values of \c Vec /// values of size 3 with the data [0,1,2], [3,4,5]. /// /// The array of components should have a number of values that divides evenly /// with the size of the Vec. If the components array does not divide evenly /// into `Vec`s, then a warning will be logged and the extra component values /// will be ignored. /// template class ArrayHandleGroupVec : public vtkm::cont::ArrayHandle< vtkm::Vec, vtkm::cont::StorageTagGroupVec> { VTKM_IS_ARRAY_HANDLE(ComponentsArrayHandleType); public: VTKM_ARRAY_HANDLE_SUBCLASS( ArrayHandleGroupVec, (ArrayHandleGroupVec), (vtkm::cont::ArrayHandle< vtkm::Vec, vtkm::cont::StorageTagGroupVec>)); using ComponentType = typename ComponentsArrayHandleType::ValueType; VTKM_CONT ArrayHandleGroupVec(const ComponentsArrayHandleType& componentsArray) : Superclass(componentsArray.GetBuffers()) { } VTKM_CONT ComponentsArrayHandleType GetComponentsArray() const { return ComponentsArrayHandleType(this->GetBuffers()); } }; /// \c make_ArrayHandleGroupVec is convenience function to generate an /// ArrayHandleGroupVec. It takes in an ArrayHandle and the number of components /// (as a specified template parameter), and returns an array handle with /// consecutive entries grouped in a Vec. /// template VTKM_CONT vtkm::cont::ArrayHandleGroupVec make_ArrayHandleGroupVec( const ArrayHandleType& array) { return vtkm::cont::ArrayHandleGroupVec(array); } //-------------------------------------------------------------------------------- // Specialization of ArrayExtractComponent namespace internal { template struct ArrayExtractComponentImpl< vtkm::cont::StorageTagGroupVec> { template vtkm::cont::ArrayHandleStride::BaseComponentType> operator()( const vtkm::cont::ArrayHandle< vtkm::Vec, vtkm::cont::StorageTagGroupVec>& src, vtkm::IdComponent componentIndex, vtkm::CopyFlag allowCopy) const { vtkm::cont::ArrayHandleGroupVec, NUM_COMPONENTS> srcArray(src); constexpr vtkm::IdComponent NUM_SUB_COMPONENTS = vtkm::VecFlat::NUM_COMPONENTS; vtkm::cont::ArrayHandleStride::BaseComponentType> dest = ArrayExtractComponentImpl{}( srcArray.GetComponentsArray(), componentIndex % NUM_SUB_COMPONENTS, allowCopy); // Adjust stride and offset to expectations of grouped values return vtkm::cont::ArrayHandleStride::BaseComponentType>( dest.GetBasicArray(), dest.GetNumberOfValues() / NUM_COMPONENTS, dest.GetStride() * NUM_COMPONENTS, dest.GetOffset() + (dest.GetStride() * (componentIndex / NUM_SUB_COMPONENTS)), dest.GetModulo(), dest.GetDivisor()); } }; } // namespace internal } } // 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_GroupVec<" + SerializableTypeString::Get() + "," + std::to_string(NUM_COMPS) + ">"; return name; } }; template struct SerializableTypeString< vtkm::cont::ArrayHandle, vtkm::cont::StorageTagGroupVec>> : SerializableTypeString< vtkm::cont::ArrayHandleGroupVec, NUM_COMPS>> { }; } } // vtkm::cont namespace mangled_diy_namespace { template struct Serialization> { private: using Type = vtkm::cont::ArrayHandleGroupVec; using BaseType = vtkm::cont::ArrayHandle; public: static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj) { vtkmdiy::save(bb, Type(obj).GetComponentsArray()); } static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj) { AH array; vtkmdiy::load(bb, array); obj = vtkm::cont::make_ArrayHandleGroupVec(array); } }; template struct Serialization< vtkm::cont::ArrayHandle, vtkm::cont::StorageTagGroupVec>> : Serialization, NUM_COMPS>> { }; } // diy /// @endcond SERIALIZATION #endif //vtk_m_cont_ArrayHandleGroupVec_h