vtk-m/vtkm/cont/ArrayHandleSwizzle.h
2024-06-05 17:51:14 -04:00

285 lines
9.6 KiB
C++

//============================================================================
// 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 <vtkm/cont/ArrayHandleTransform.h>
#include <vtkm/VecTraits.h>
#include <vtkmstd/integer_sequence.h>
namespace vtkm
{
namespace internal
{
template <typename InType, typename OutType>
class SwizzleFunctor
{
using InTraits = vtkm::VecTraits<InType>;
using InComponentType = typename InTraits::ComponentType;
static constexpr vtkm::IdComponent NUM_IN_COMPONENTS = InTraits::NUM_COMPONENTS;
using OutTraits = vtkm::VecTraits<OutType>;
using OutComponentType = typename OutTraits::ComponentType;
static constexpr vtkm::IdComponent NUM_OUT_COMPONENTS = OutTraits::NUM_COMPONENTS;
template <vtkm::IdComponent... Is>
using IndexSequence = vtkmstd::integer_sequence<vtkm::IdComponent, Is...>;
using IndexList = vtkmstd::make_integer_sequence<vtkm::IdComponent, NUM_OUT_COMPONENTS>;
public:
using MapType = vtkm::Vec<vtkm::IdComponent, NUM_OUT_COMPONENTS>;
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::IdComponent... Is>
VTKM_CONT static MapType IndexListAsMap(IndexSequence<Is...>)
{
return { Is... };
}
template <vtkm::IdComponent... Is>
VTKM_EXEC_CONT OutType Swizzle(const InType& vec, IndexSequence<Is...>) const
{
return { InTraits::GetComponent(vec, this->Map[Is])... };
}
MapType Map = InitMap();
};
namespace detail
{
template <typename InType, typename OutType, typename Invertible>
struct GetInverseSwizzleImpl;
template <typename InType, typename OutType>
struct GetInverseSwizzleImpl<InType, OutType, std::true_type>
{
using Type = vtkm::internal::SwizzleFunctor<OutType, InType>;
template <typename ForwardMapType>
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 <typename InType, typename OutType>
struct GetInverseSwizzleImpl<InType, OutType, std::false_type>
{
using Type = vtkm::cont::internal::NullFunctorType;
template <typename ForwardMapType>
VTKM_CONT static Type Value(const ForwardMapType&)
{
return Type{};
}
};
template <typename InType, typename OutType>
using SwizzleInvertible = std::integral_constant<bool,
vtkm::VecTraits<InType>::NUM_COMPONENTS ==
vtkm::VecTraits<OutType>::NUM_COMPONENTS>;
} // namespace detail
template <typename InType, typename OutType>
VTKM_CONT vtkm::internal::SwizzleFunctor<InType, OutType> GetSwizzleFunctor(
const typename vtkm::internal::SwizzleFunctor<InType, OutType>::MapType& forwardMap)
{
return vtkm::internal::SwizzleFunctor<InType, OutType>(forwardMap);
}
template <typename InType, typename OutType>
using InverseSwizzleType = typename detail::
GetInverseSwizzleImpl<InType, OutType, detail::SwizzleInvertible<InType, OutType>>::Type;
template <typename InType, typename OutType>
VTKM_CONT InverseSwizzleType<InType, OutType> GetInverseSwizzleFunctor(
const typename vtkm::internal::SwizzleFunctor<InType, OutType>::MapType& forwardMap)
{
return detail::
GetInverseSwizzleImpl<InType, OutType, detail::SwizzleInvertible<InType, OutType>>::Value(
forwardMap);
}
}
} // namespace vtkm::internal
namespace vtkm
{
namespace cont
{
namespace detail
{
template <typename ArrayHandleType, vtkm::IdComponent OutSize>
struct ArrayHandleSwizzleTraits
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
using InType = typename ArrayHandleType::ValueType;
using OutType = vtkm::Vec<typename vtkm::VecTraits<InType>::ComponentType, OutSize>;
using SwizzleFunctor = vtkm::internal::SwizzleFunctor<InType, OutType>;
using InverseSwizzleFunctor = vtkm::internal::InverseSwizzleType<InType, OutType>;
using MapType = typename SwizzleFunctor::MapType;
static SwizzleFunctor GetFunctor(const MapType& forwardMap)
{
return vtkm::internal::GetSwizzleFunctor<InType, OutType>(forwardMap);
}
static InverseSwizzleFunctor GetInverseFunctor(const MapType& forwardMap)
{
return vtkm::internal::GetInverseSwizzleFunctor<InType, OutType>(forwardMap);
}
using Superclass =
vtkm::cont::ArrayHandleTransform<ArrayHandleType, SwizzleFunctor, InverseSwizzleFunctor>;
};
} // 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 <typename ArrayHandleType, vtkm::IdComponent OutSize>
class ArrayHandleSwizzle
: public detail::ArrayHandleSwizzleTraits<ArrayHandleType, OutSize>::Superclass
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
using Traits = detail::ArrayHandleSwizzleTraits<ArrayHandleType, OutSize>;
public:
VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleSwizzle,
(ArrayHandleSwizzle<ArrayHandleType, OutSize>),
(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 <typename ArrayHandleType, vtkm::IdComponent OutSize>
VTKM_CONT ArrayHandleSwizzle<ArrayHandleType, OutSize> make_ArrayHandleSwizzle(
const ArrayHandleType& array,
const vtkm::Vec<vtkm::IdComponent, OutSize>& map)
{
return ArrayHandleSwizzle<ArrayHandleType, OutSize>(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 <typename ArrayHandleType, typename... SwizzleIndexTypes>
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 <typename InType, typename OutType>
struct SerializableTypeString<vtkm::internal::SwizzleFunctor<InType, OutType>>
{
static VTKM_CONT const std::string& Get()
{
static std::string name = "Swizzle<" + SerializableTypeString<InType>::Get() + "," +
SerializableTypeString<OutType>::Get() + ">";
return name;
}
};
template <typename AH, vtkm::IdComponent NComps>
struct SerializableTypeString<vtkm::cont::ArrayHandleSwizzle<AH, NComps>>
: SerializableTypeString<typename vtkm::cont::ArrayHandleSwizzle<AH, NComps>::Superclass>
{
};
}
} // vtkm::cont
namespace mangled_diy_namespace
{
template <typename AH, vtkm::IdComponent NComps>
struct Serialization<vtkm::cont::ArrayHandleSwizzle<AH, NComps>>
: Serialization<typename vtkm::cont::ArrayHandleSwizzle<AH, NComps>::Superclass>
{
};
} // diy
/// @endcond SERIALIZATION
#endif // vtk_m_cont_ArrayHandleSwizzle_h