//============================================================================ // 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_ArrayHandleSwizzle_h #define vtk_m_cont_ArrayHandleSwizzle_h #include #include #include namespace vtkm { namespace internal { template class SwizzleFunctor { using InTraits = vtkm::VecTraits; using InComponentType = typename InTraits::ComponentType; static constexpr vtkm::IdComponent NUM_IN_COMPONENTS = InTraits::NUM_COMPONENTS; using OutTraits = vtkm::VecTraits; using OutComponentType = typename OutTraits::ComponentType; static constexpr vtkm::IdComponent NUM_OUT_COMPONENTS = OutTraits::NUM_COMPONENTS; template using IndexSequence = vtkmstd::integer_sequence; using IndexList = vtkmstd::make_integer_sequence; public: using MapType = vtkm::Vec; VTKM_CONT SwizzleFunctor(const MapType& map) : Map(map) { } VTKM_CONT SwizzleFunctor() = default; VTKM_EXEC_CONT OutType operator()(const InType& vec) const { return this->Swizzle(vec, IndexList{}); } VTKM_CONT static MapType InitMap() { return IndexListAsMap(IndexList{}); } private: template VTKM_CONT static MapType IndexListAsMap(IndexSequence) { return { Is... }; } template VTKM_EXEC_CONT OutType Swizzle(const InType& vec, IndexSequence) const { return { InTraits::GetComponent(vec, this->Map[Is])... }; } MapType Map = InitMap(); }; namespace detail { template struct GetInverseSwizzleImpl; template struct GetInverseSwizzleImpl { using Type = vtkm::internal::SwizzleFunctor; template VTKM_CONT static Type Value(const ForwardMapType& forwardMap) { // Note that when reversing the map, if the forwardMap repeats any indices, then // the map is not 1:1 and is not invertible. We cannot check that at compile time. // In this case, results can become unpredictible. using InverseMapType = typename Type::MapType; InverseMapType inverseMap = Type::InitMap(); for (vtkm::IdComponent inIndex = 0; inIndex < ForwardMapType::NUM_COMPONENTS; ++inIndex) { inverseMap[forwardMap[inIndex]] = inIndex; } return Type(inverseMap); } }; template struct GetInverseSwizzleImpl { using Type = vtkm::cont::internal::NullFunctorType; template VTKM_CONT static Type Value(const ForwardMapType&) { return Type{}; } }; template using SwizzleInvertible = std::integral_constant::NUM_COMPONENTS == vtkm::VecTraits::NUM_COMPONENTS>; } // namespace detail template VTKM_CONT vtkm::internal::SwizzleFunctor GetSwizzleFunctor( const typename vtkm::internal::SwizzleFunctor::MapType& forwardMap) { return vtkm::internal::SwizzleFunctor(forwardMap); } template using InverseSwizzleType = typename detail:: GetInverseSwizzleImpl>::Type; template VTKM_CONT InverseSwizzleType GetInverseSwizzleFunctor( const typename vtkm::internal::SwizzleFunctor::MapType& forwardMap) { return detail:: GetInverseSwizzleImpl>::Value( forwardMap); } } } // namespace vtkm::internal namespace vtkm { namespace cont { namespace detail { template struct ArrayHandleSwizzleTraits { VTKM_IS_ARRAY_HANDLE(ArrayHandleType); using InType = typename ArrayHandleType::ValueType; using OutType = vtkm::Vec::ComponentType, OutSize>; using SwizzleFunctor = vtkm::internal::SwizzleFunctor; using InverseSwizzleFunctor = vtkm::internal::InverseSwizzleType; using MapType = typename SwizzleFunctor::MapType; static SwizzleFunctor GetFunctor(const MapType& forwardMap) { return vtkm::internal::GetSwizzleFunctor(forwardMap); } static InverseSwizzleFunctor GetInverseFunctor(const MapType& forwardMap) { return vtkm::internal::GetInverseSwizzleFunctor(forwardMap); } using Superclass = vtkm::cont::ArrayHandleTransform; }; } // namespace detail /// \brief Swizzle the components of the values in an `ArrayHandle`. /// /// Given an `ArrayHandle` with `Vec` values, `ArrayHandleSwizzle` allows you to /// reorder the components of all the `Vec` values. This reordering is done in place, /// so the array does not have to be duplicated. /// /// The resulting array does not have to contain all of the components of the input. /// For example, you could use `ArrayHandleSwizzle` to drop one of the components of /// each vector. However, if you do that, then the swizzled array is read-only. If /// there is a 1:1 map from input components to output components, writing to the /// array will be enabled. /// /// The swizzle map given to `ArrayHandleSwizzle` must comprise valid component indices /// (between 0 and number of components - 1). Also, the component indices should not /// be repeated, particularly if you expect to write to the array. These conditions are /// not checked. /// template class ArrayHandleSwizzle : public detail::ArrayHandleSwizzleTraits::Superclass { VTKM_IS_ARRAY_HANDLE(ArrayHandleType); using Traits = detail::ArrayHandleSwizzleTraits; public: VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleSwizzle, (ArrayHandleSwizzle), (typename Traits::Superclass)); using MapType = typename Traits::MapType; /// Construct an `ArrayHandleSwizzle` with a source array and a swizzle map. /// The swizzle map is a `vtkm::Vec` containing `vtkm::IdComponent` components /// and sized to the number of components in the array. Each value in the map /// specifies from which component of the input the corresponding component of /// the output should come from. VTKM_CONT ArrayHandleSwizzle(const ArrayHandleType& array, const MapType& map) : Superclass(array, Traits::GetFunctor(map), Traits::GetInverseFunctor(map)) { } }; /// Construct an `ArrayHandleSwizzle` from a provided array and swizzle map. /// The swizzle map is a `vtkm::Vec` containing `vtkm::IdComponent` components /// and sized to the number of components in the array. Each value in the map /// specifies from which component of the input the corresponding component of /// the output should come from. template VTKM_CONT ArrayHandleSwizzle make_ArrayHandleSwizzle( const ArrayHandleType& array, const vtkm::Vec& map) { return ArrayHandleSwizzle(array, map); } /// Construct an `ArrayHandleSwizzle` from a provided array and swizzle map. /// The swizzle map is specified as independent function parameters after the array. /// Each value in the map specifies from which component of the input the corresponding /// component of the output should come from. template VTKM_CONT auto make_ArrayHandleSwizzle(const ArrayHandleType& array, vtkm::IdComponent swizzleIndex0, SwizzleIndexTypes... swizzleIndices) { return make_ArrayHandleSwizzle(array, vtkm::make_Vec(swizzleIndex0, swizzleIndices...)); } } } // 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 = "Swizzle<" + SerializableTypeString::Get() + "," + SerializableTypeString::Get() + ">"; return name; } }; template struct SerializableTypeString> : SerializableTypeString::Superclass> { }; } } // vtkm::cont namespace mangled_diy_namespace { template struct Serialization> : Serialization::Superclass> { }; } // diy /// @endcond SERIALIZATION #endif // vtk_m_cont_ArrayHandleSwizzle_h