//============================================================================ // 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_ArrayHandleCompositeVector_h #define vtk_m_ArrayHandleCompositeVector_h #include #include #include #include #include #include #include #include #include namespace vtkm { namespace internal { namespace compvec { template using AllPortalsAreWritable = vtkm::ListAll, vtkm::internal::PortalSupportsSets>; // GetValueType: --------------------------------------------------------------- // Determines the output `ValueType` of the set of `ArrayHandle` objects. For example, if the input // set contains 3 types with `vtkm::Float32` ValueTypes, then the ValueType defined here will be // `vtkm::Vec`. This also validates that all members have the same `ValueType`. template struct CheckValueType { VTKM_STATIC_ASSERT_MSG((std::is_same::value), "ArrayHandleCompositeVector must be built from " "ArrayHandles with the same ValueTypes."); }; template struct GetValueType { static constexpr vtkm::IdComponent COUNT = static_cast(sizeof...(ArrayTypes)) + 1; using ComponentType = typename ArrayType0::ValueType; using ValueCheck = vtkm::List...>; using ValueType = vtkm::Vec; }; // Special case for only one component template struct GetValueType { static constexpr vtkm::IdComponent COUNT = 1; using ComponentType = typename ArrayType::ValueType; using ValueType = typename ArrayType::ValueType; }; // GetFromPortals: ------------------------------------------------------------- // Given a set of array portals as arguments, returns a Vec comprising the values // at the provided index. VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT typename GetValueType::ValueType GetFromPortals( vtkm::Id index, const Portals&... portals) { return { portals.Get(index)... }; } // SetToPortals: --------------------------------------------------------------- // Given a Vec-like object, and index, and a set of array portals, sets each of // the portals to the respective component of the Vec. VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void SetToPortalsImpl(vtkm::Id index, const ValueType& value, vtkmstd::integer_sequence, const Portals&... portals) { using Traits = vtkm::VecTraits; (void)std::initializer_list{ (portals.Set(index, Traits::GetComponent(value, I)), false)... }; } VTKM_SUPPRESS_EXEC_WARNINGS template VTKM_EXEC_CONT void SetToPortals(vtkm::Id index, const ValueType& value, const Portals&... portals) { SetToPortalsImpl( index, value, vtkmstd::make_integer_sequence{}, portals...); } } // namespace compvec template class VTKM_ALWAYS_EXPORT ArrayPortalCompositeVector { using Writable = compvec::AllPortalsAreWritable; using TupleType = vtkm::Tuple; TupleType Portals; public: using ValueType = typename compvec::GetValueType::ValueType; VTKM_EXEC_CONT ArrayPortalCompositeVector() {} VTKM_CONT ArrayPortalCompositeVector(const PortalTypes&... portals) : Portals(portals...) { } VTKM_CONT ArrayPortalCompositeVector(const TupleType& portals) : Portals(portals) { } VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const { return vtkm::Get<0>(this->Portals).GetNumberOfValues(); } VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const { return this->Portals.Apply(compvec::GetFromPortals, index); } template ::type> VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const { this->Portals.Apply(compvec::SetToPortals, index, value); } }; } } // vtkm::internal namespace vtkm { namespace cont { namespace internal { namespace compvec { template struct VerifyArrayHandle { VTKM_STATIC_ASSERT_MSG(vtkm::cont::internal::ArrayHandleCheck::type::value, "Template parameters for ArrayHandleCompositeVector " "must be a list of ArrayHandle types."); }; } // end namespace compvec } // namespace internal template struct VTKM_ALWAYS_EXPORT StorageTagCompositeVec { }; namespace internal { template struct CompositeVectorTraits { // Need to check this here, since this traits struct is used in the // ArrayHandleCompositeVector superclass definition before any other // static_asserts could be used. using CheckArrayHandles = vtkm::List...>; using ValueType = typename vtkm::internal::compvec::GetValueType::ValueType; using StorageTag = vtkm::cont::StorageTagCompositeVec; using StorageType = Storage; using Superclass = ArrayHandle; }; template class Storage(sizeof...(StorageTags))>, vtkm::cont::StorageTagCompositeVec> { using ValueType = vtkm::Vec(sizeof...(StorageTags))>; struct Info { std::array BufferOffset; }; template using StorageFor = vtkm::cont::internal::Storage; using StorageTuple = vtkm::Tuple...>; VTKM_CONT static std::vector GetBuffers( const std::vector& buffers, std::size_t subArray) { Info info = buffers[0].GetMetaData(); return std::vector(buffers.begin() + info.BufferOffset[subArray], buffers.begin() + info.BufferOffset[subArray + 1]); } template VTKM_CONT static std::vector Buffers( const std::vector& buffers) { return GetBuffers(buffers, I); } using IndexList = vtkmstd::make_index_sequence; public: using ReadPortalType = vtkm::internal::ArrayPortalCompositeVector::ReadPortalType...>; using WritePortalType = vtkm::internal::ArrayPortalCompositeVector< typename StorageFor::WritePortalType...>; private: template static void ResizeBuffersImpl(vtkmstd::index_sequence, vtkm::Id numValues, const std::vector& buffers, vtkm::CopyFlag preserve, vtkm::cont::Token& token) { std::vector> bufferPartitions = { Buffers( buffers)... }; auto init_list = { (vtkm::tuple_element_t::ResizeBuffers( numValues, bufferPartitions[Is], preserve, token), false)... }; (void)init_list; } template static void FillImpl(vtkmstd::index_sequence, const std::vector& buffers, const ValueType& fillValue, vtkm::Id startIndex, vtkm::Id endIndex, vtkm::cont::Token& token) { auto init_list = { ( vtkm::tuple_element_t::Fill(Buffers(buffers), fillValue[static_cast(Is)], startIndex, endIndex, token), false)... }; (void)init_list; } template static ReadPortalType CreateReadPortalImpl( vtkmstd::index_sequence, const std::vector& buffers, vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) { return ReadPortalType(vtkm::tuple_element_t::CreateReadPortal( Buffers(buffers), device, token)...); } template static WritePortalType CreateWritePortalImpl( vtkmstd::index_sequence, const std::vector& buffers, vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) { return WritePortalType(vtkm::tuple_element_t::CreateWritePortal( Buffers(buffers), device, token)...); } public: VTKM_CONT static vtkm::Id GetNumberOfValues( const std::vector& buffers) { return vtkm::TupleElement<0, StorageTuple>::GetNumberOfValues(Buffers<0>(buffers)); } VTKM_CONT static void ResizeBuffers(vtkm::Id numValues, const std::vector& buffers, vtkm::CopyFlag preserve, vtkm::cont::Token& token) { ResizeBuffersImpl(IndexList{}, numValues, buffers, preserve, token); } VTKM_CONT static void Fill(const std::vector& buffers, const ValueType& fillValue, vtkm::Id startIndex, vtkm::Id endIndex, vtkm::cont::Token& token) { FillImpl(IndexList{}, buffers, fillValue, startIndex, endIndex, token); } VTKM_CONT static ReadPortalType CreateReadPortal( const std::vector& buffers, vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) { return CreateReadPortalImpl(IndexList{}, buffers, device, token); } VTKM_CONT static WritePortalType CreateWritePortal( const std::vector& buffers, vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) { return CreateWritePortalImpl(IndexList{}, buffers, device, token); } public: VTKM_CONT static std::vector CreateBuffers( const vtkm::cont::ArrayHandle&... arrays) { auto numBuffers = { std::size_t{ 1 }, arrays.GetBuffers().size()... }; Info info; std::partial_sum(numBuffers.begin(), numBuffers.end(), info.BufferOffset.begin()); return vtkm::cont::internal::CreateBuffers(info, arrays...); } VTKM_CONT static std::vector CreateBuffers() { return CreateBuffers(vtkm::cont::ArrayHandle{}...); } private: using ArrayTupleType = vtkm::Tuple...>; template VTKM_CONT static ArrayTupleType GetArrayTupleImpl( vtkmstd::index_sequence, const std::vector& buffers) { return ArrayTupleType(vtkm::cont::ArrayHandle(Buffers(buffers))...); } public: VTKM_CONT static ArrayTupleType GetArrayTuple( const std::vector& buffers) { return GetArrayTupleImpl(IndexList{}, buffers); } }; // Special degenerative case when there is only one array being composited template struct Storage> : Storage { VTKM_CONT static std::vector CreateBuffers( const vtkm::cont::ArrayHandle& array = vtkm::cont::ArrayHandle{}) { return vtkm::cont::internal::CreateBuffers(array); } VTKM_CONT static vtkm::Tuple> GetArrayTuple( const std::vector& buffers) { return vtkm::cont::ArrayHandle(buffers); } }; } // namespace internal /// \brief An \c ArrayHandle that combines components from other arrays. /// /// \c ArrayHandleCompositeVector is a specialization of \c ArrayHandle that /// derives its content from other arrays. It takes any number of /// single-component \c ArrayHandle objects and mimics an array that contains /// vectors with components that come from these delegate arrays. /// /// The easiest way to create and type an \c ArrayHandleCompositeVector is /// to use the \c make_ArrayHandleCompositeVector functions. /// /// The \c ArrayHandleExtractComponent class may be helpful when a desired /// component is part of an \c ArrayHandle with a \c vtkm::Vec \c ValueType. /// template class ArrayHandleCompositeVector : public ArrayHandle::ValueType, typename internal::CompositeVectorTraits::StorageTag> { private: using Traits = internal::CompositeVectorTraits; using StorageType = typename Traits::StorageType; public: VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleCompositeVector, (ArrayHandleCompositeVector), (typename Traits::Superclass)); VTKM_CONT ArrayHandleCompositeVector(const ArrayTs&... arrays) : Superclass(StorageType::CreateBuffers(arrays...)) { } VTKM_CONT vtkm::Tuple GetArrayTuple() const { return StorageType::GetArrayTuple(this->GetBuffers()); } }; /// Create a composite vector array from other arrays. /// template VTKM_CONT ArrayHandleCompositeVector make_ArrayHandleCompositeVector( const ArrayTs&... arrays) { // Will issue compiler error if any of ArrayTs is not a valid ArrayHandle. vtkm::List...> checkArrayHandles; (void)checkArrayHandles; return ArrayHandleCompositeVector(arrays...); } //-------------------------------------------------------------------------------- // Specialization of ArrayExtractComponent namespace internal { namespace detail { template struct ExtractComponentCompositeVecFunctor { using ResultArray = vtkm::cont::ArrayHandleStride::BaseComponentType>; ResultArray operator()(vtkm::IdComponent, vtkm::IdComponent, vtkm::CopyFlag) const { throw vtkm::cont::ErrorBadValue("Invalid component index given to ArrayExtractComponent."); } template ResultArray operator()(vtkm::IdComponent compositeIndex, vtkm::IdComponent subIndex, vtkm::CopyFlag allowCopy, const A0& array0, const As&... arrays) const { if (compositeIndex == 0) { return vtkm::cont::internal::ArrayExtractComponentImpl{}( array0, subIndex, allowCopy); } else { return (*this)(--compositeIndex, subIndex, allowCopy, arrays...); } } }; } // namespace detail // Superclass will inherit the ArrayExtractComponentImplInefficient property if any // of the sub-storage are inefficient (thus making everything inefficient). template struct ArrayExtractComponentImpl> : vtkm::cont::internal::ArrayExtractComponentImplInherit { template auto operator()( const vtkm::cont::ArrayHandle>& src, vtkm::IdComponent componentIndex, vtkm::CopyFlag allowCopy) const { using T = typename vtkm::VecTraits::ComponentType; vtkm::cont::ArrayHandleCompositeVector...> array(src); constexpr vtkm::IdComponent NUM_SUB_COMPONENTS = vtkm::VecFlat::NUM_COMPONENTS; return array.GetArrayTuple().Apply(detail::ExtractComponentCompositeVecFunctor{}, componentIndex / NUM_SUB_COMPONENTS, componentIndex % NUM_SUB_COMPONENTS, allowCopy); } }; } // 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_CompositeVector<" + internal::GetVariadicSerializableTypeString(AHs{}...) + ">"; return name; } }; template struct SerializableTypeString< vtkm::cont::ArrayHandle(sizeof...(STs))>, vtkm::cont::StorageTagCompositeVec>> : SerializableTypeString< vtkm::cont::ArrayHandleCompositeVector...>> { }; } } // vtkm::cont namespace mangled_diy_namespace { template struct Serialization> { private: using Type = typename vtkm::cont::ArrayHandleCompositeVector; using BaseType = vtkm::cont::ArrayHandle; struct SaveFunctor { BinaryBuffer& Buffer; SaveFunctor(BinaryBuffer& bb) : Buffer(bb) { } template void operator()(const AH& ah) const { vtkmdiy::save(this->Buffer, ah); } }; struct LoadFunctor { BinaryBuffer& Buffer; LoadFunctor(BinaryBuffer& bb) : Buffer(bb) { } template void operator()(AH& ah) const { vtkmdiy::load(this->Buffer, ah); } }; static BaseType Create(const AHs&... arrays) { return Type(arrays...); } public: static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj) { Type(obj).GetArrayTuple().ForEach(SaveFunctor{ bb }); } static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj) { vtkm::Tuple tuple; tuple.ForEach(LoadFunctor{ bb }); obj = tuple.Apply(Create); } }; template struct Serialization< vtkm::cont::ArrayHandle(sizeof...(STs))>, vtkm::cont::StorageTagCompositeVec>> : Serialization...>> { }; } // diy /// @endcond SERIALIZATION #endif //vtk_m_ArrayHandleCompositeVector_h