//============================================================================ // 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_VecFlat_h #define vtk_m_VecFlat_h #include #include #include #include namespace vtkm { namespace internal { template ::HasMultipleComponents> struct TotalNumComponents; template struct TotalNumComponents { VTKM_STATIC_ASSERT_MSG( (std::is_same::IsSizeStatic, vtkm::VecTraitsTagSizeStatic>::value), "vtkm::VecFlat can only be used with Vec types with a static number of components."); using ComponentType = typename vtkm::VecTraits::ComponentType; static constexpr vtkm::IdComponent value = vtkm::VecTraits::NUM_COMPONENTS * TotalNumComponents::value; }; template struct TotalNumComponents { static constexpr vtkm::IdComponent value = 1; }; template using FlattenVec = vtkm::Vec::BaseComponentType, vtkm::internal::TotalNumComponents::value>; template using IsFlatVec = typename std::is_same>::type; namespace detail { template VTKM_EXEC_CONT T GetFlatVecComponentImpl(const T& component, vtkm::IdComponent index, std::true_type vtkmNotUsed(isBase)) { VTKM_ASSERT(index == 0); return component; } template VTKM_EXEC_CONT typename vtkm::VecTraits::BaseComponentType GetFlatVecComponentImpl(const T& vec, vtkm::IdComponent index, std::false_type vtkmNotUsed(isBase)) { using Traits = vtkm::VecTraits; using ComponentType = typename Traits::ComponentType; using BaseComponentType = typename Traits::BaseComponentType; constexpr vtkm::IdComponent subSize = TotalNumComponents::value; return GetFlatVecComponentImpl(Traits::GetComponent(vec, index / subSize), index % subSize, typename std::is_same::type{}); } } // namespace detail template VTKM_EXEC_CONT typename vtkm::VecTraits::BaseComponentType GetFlatVecComponent( const T& vec, vtkm::IdComponent index) { return detail::GetFlatVecComponentImpl(vec, index, std::false_type{}); } namespace detail { template VTKM_EXEC_CONT void CopyVecNestedToFlatImpl(T nestedVec, vtkm::Vec& flatVec, vtkm::IdComponent flatOffset) { flatVec[flatOffset] = nestedVec; } template VTKM_EXEC_CONT void CopyVecNestedToFlatImpl(const vtkm::Vec& nestedVec, vtkm::Vec& flatVec, vtkm::IdComponent flatOffset) { for (vtkm::IdComponent nestedIndex = 0; nestedIndex < NNest; ++nestedIndex) { flatVec[nestedIndex + flatOffset] = nestedVec[nestedIndex]; } } template VTKM_EXEC_CONT void CopyVecNestedToFlatImpl(const NestedVecType& nestedVec, vtkm::Vec& flatVec, vtkm::IdComponent flatOffset) { using Traits = vtkm::VecTraits; using ComponentType = typename Traits::ComponentType; constexpr vtkm::IdComponent subSize = TotalNumComponents::value; vtkm::IdComponent flatIndex = flatOffset; for (vtkm::IdComponent nestIndex = 0; nestIndex < Traits::NUM_COMPONENTS; ++nestIndex) { CopyVecNestedToFlatImpl(Traits::GetComponent(nestedVec, nestIndex), flatVec, flatIndex); flatIndex += subSize; } } } // namespace detail template VTKM_EXEC_CONT void CopyVecNestedToFlat(const NestedVecType& nestedVec, vtkm::Vec& flatVec) { detail::CopyVecNestedToFlatImpl(nestedVec, flatVec, 0); } namespace detail { template VTKM_EXEC_CONT void CopyVecFlatToNestedImpl(const vtkm::Vec& flatVec, vtkm::IdComponent flatOffset, T& nestedVec) { nestedVec = flatVec[flatOffset]; } template VTKM_EXEC_CONT void CopyVecFlatToNestedImpl(const vtkm::Vec& flatVec, vtkm::IdComponent flatOffset, vtkm::Vec& nestedVec) { for (vtkm::IdComponent nestedIndex = 0; nestedIndex < NNest; ++nestedIndex) { nestedVec[nestedIndex] = flatVec[nestedIndex + flatOffset]; } } template VTKM_EXEC_CONT void CopyVecFlatToNestedImpl(const vtkm::Vec& flatVec, vtkm::IdComponent flatOffset, vtkm::Vec& nestedVec) { constexpr vtkm::IdComponent subSize = TotalNumComponents::value; vtkm::IdComponent flatIndex = flatOffset; for (vtkm::IdComponent nestIndex = 0; nestIndex < NNest; ++nestIndex) { CopyVecFlatToNestedImpl(flatVec, flatIndex, nestedVec[nestIndex]); flatIndex += subSize; } } template VTKM_EXEC_CONT void CopyVecFlatToNestedImpl(const vtkm::Vec& flatVec, vtkm::IdComponent flatOffset, NestedVecType& nestedVec) { using Traits = vtkm::VecTraits; using ComponentType = typename Traits::ComponentType; constexpr vtkm::IdComponent subSize = TotalNumComponents::value; vtkm::IdComponent flatIndex = flatOffset; for (vtkm::IdComponent nestIndex = 0; nestIndex < Traits::NUM_COMPONENTS; ++nestIndex) { ComponentType component; CopyVecFlatToNestedImpl(flatVec, flatIndex, component); Traits::SetComponent(nestedVec, nestIndex, component); flatIndex += subSize; } } } // namespace detail template VTKM_EXEC_CONT void CopyVecFlatToNested(const vtkm::Vec& flatVec, NestedVecType& nestedVec) { detail::CopyVecFlatToNestedImpl(flatVec, 0, nestedVec); } } // namespace internal /// \brief Treat a `Vec` or `Vec`-like object as a flat `Vec`. /// /// The `VecFlat` template wraps around another object that is a nested `Vec` object /// (that is, a vector of vectors) and treats it like a flat, 1 dimensional `Vec`. /// For example, let's say that you have a `Vec` of size 3 holding `Vec`s of size 2. /// /// ```cpp /// void Foo(const vtkm::Vec, 3>& nestedVec) /// { /// auto flatVec = vtkm::make_VecFlat(nestedVec); /// ``` /// /// `flatVec` is now of type `vtkm::VecFlat, 3>`. /// `flatVec::NUM_COMPONENTS` is 6 (3 * 2). The `[]` operator takes an index between /// 0 and 5 and returns a value of type `vtkm::Id`. The indices are explored in /// depth-first order. So `flatVec[0] == nestedVec[0][0]`, `flatVec[1] == nestedVec[0][1]`, /// `flatVec[2] == nestedVec[1][0]`, and so on. /// /// Note that `flatVec` only works with types that have `VecTraits` defined where /// the `IsSizeStatic` field is `vtkm::VecTraitsTagSizeStatic` (that is, the `NUM_COMPONENTS` /// constant is defined). /// template ::value> class VecFlat; // Case where T is not a vtkm::Vec where T is not a Vec. template class VecFlat : public internal::FlattenVec { using Superclass = internal::FlattenVec; public: using Superclass::Superclass; VecFlat() = default; VTKM_EXEC_CONT VecFlat(const T& src) { *this = src; } VTKM_EXEC_CONT VecFlat& operator=(const T& src) { internal::CopyVecNestedToFlat(src, *this); return *this; } VTKM_EXEC_CONT operator T() const { T nestedVec; internal::CopyVecFlatToNested(*this, nestedVec); return nestedVec; } }; // Specialization of VecFlat where the Vec is already flat Vec template class VecFlat : public T { public: using T::T; VecFlat() = default; VTKM_EXEC_CONT VecFlat(const T& src) : T(src) { } VTKM_EXEC_CONT VecFlat& operator=(const T& src) { this->T::operator=(src); return *this; } VTKM_EXEC_CONT VecFlat& operator=(T&& src) { this->T::operator=(std::move(src)); return *this; } }; /// \brief Converts a `Vec`-like object to a `VecFlat`. /// template VTKM_EXEC_CONT vtkm::VecFlat make_VecFlat(const T& vec) { return vtkm::VecFlat(vec); } template struct TypeTraits> : TypeTraits> { }; template struct VecTraits> : VecTraits> { }; } // namespace vtkm #endif //vtk_m_VecFlat_h