//============================================================================ // 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_ArrayHandleCast_h #define vtk_m_cont_ArrayHandleCast_h #include #include #include #include #include namespace vtkm { namespace cont { namespace internal { template struct VTKM_ALWAYS_EXPORT Cast { VTKM_EXEC_CONT ToType operator()(const FromType& val) const { return static_cast(val); } }; } // namespace internal /// \brief Cast the values of an array to the specified type, on demand. /// /// ArrayHandleCast is a specialization of ArrayHandleTransform. Given an ArrayHandle /// and a type, it creates a new handle that returns the elements of the array cast /// to the specified type. /// template class ArrayHandleCast : public vtkm::cont::ArrayHandleTransform, internal::Cast> { public: VTKM_ARRAY_HANDLE_SUBCLASS( ArrayHandleCast, (ArrayHandleCast), (vtkm::cont::ArrayHandleTransform, internal::Cast>)); ArrayHandleCast(const ArrayHandleType& handle) : Superclass(handle) { this->ValidateTypeCast(); } /// Implemented so that it is defined exclusively in the control environment. /// If there is a separate device for the execution environment (for example, /// with CUDA), then the automatically generated destructor could be /// created for all devices, and it would not be valid for all devices. /// ~ArrayHandleCast() {} private: // Log warnings if type cast is valid but lossy: template VTKM_CONT static typename std::enable_if::value>::type ValidateTypeCast() { #ifdef VTKM_ENABLE_LOGGING using DstValueType = T; using SrcComp = typename vtkm::VecTraits::BaseComponentType; using DstComp = typename vtkm::VecTraits::BaseComponentType; using SrcLimits = std::numeric_limits; using DstLimits = std::numeric_limits; const vtkm::Range SrcRange{ SrcLimits::min(), SrcLimits::max() }; const vtkm::Range DstRange{ DstLimits::min(), DstLimits::max() }; const bool RangeLoss = (SrcRange.Max > DstRange.Max || SrcRange.Min < DstRange.Min); const bool PrecLoss = SrcLimits::digits > DstLimits::digits; if (RangeLoss && PrecLoss) { VTKM_LOG_F(vtkm::cont::LogLevel::Warn, "VariantArrayHandle::AsVirtual: Casting ComponentType of " "%s to %s reduces range and precision.", vtkm::cont::TypeToString().c_str(), vtkm::cont::TypeToString().c_str()); } else if (RangeLoss) { VTKM_LOG_F(vtkm::cont::LogLevel::Warn, "VariantArrayHandle::AsVirtual: Casting ComponentType of " "%s to %s reduces range.", vtkm::cont::TypeToString().c_str(), vtkm::cont::TypeToString().c_str()); } else if (PrecLoss) { VTKM_LOG_F(vtkm::cont::LogLevel::Warn, "VariantArrayHandle::AsVirtual: Casting ComponentType of " "%s to %s reduces precision.", vtkm::cont::TypeToString().c_str(), vtkm::cont::TypeToString().c_str()); } #endif // Logging } template VTKM_CONT static typename std::enable_if::value>::type ValidateTypeCast() { //no-op if types match } }; namespace detail { template struct MakeArrayHandleCastImpl { using ReturnType = vtkm::cont::ArrayHandleCast; VTKM_CONT static ReturnType DoMake(const ArrayType& array) { return ReturnType(array); } }; template struct MakeArrayHandleCastImpl { using ReturnType = ArrayType; VTKM_CONT static ReturnType DoMake(const ArrayType& array) { return array; } }; } // namespace detail /// make_ArrayHandleCast is convenience function to generate an /// ArrayHandleCast. /// template VTKM_CONT typename detail::MakeArrayHandleCastImpl::ReturnType make_ArrayHandleCast(const ArrayType& array, const T& = T()) { VTKM_IS_ARRAY_HANDLE(ArrayType); using MakeImpl = detail::MakeArrayHandleCastImpl; return MakeImpl::DoMake(array); } } } // 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_Cast_Functor<" + SerializableTypeString::Get() + "," + SerializableTypeString::Get() + ">"; return name; } }; template struct SerializableTypeString> : SerializableTypeString< vtkm::cont::ArrayHandleTransform, vtkm::cont::internal::Cast>> { }; } } // namespace vtkm::cont namespace mangled_diy_namespace { template struct Serialization> { static VTKM_CONT void save(BinaryBuffer&, const vtkm::cont::internal::Cast&) {} static VTKM_CONT void load(BinaryBuffer&, vtkm::cont::internal::Cast&) {} }; template struct Serialization> : Serialization< vtkm::cont::ArrayHandleTransform, vtkm::cont::internal::Cast>> { }; } // diy /// @endcond SERIALIZATION #endif // vtk_m_cont_ArrayHandleCast_h