//============================================================================ // 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_ArrayHandleVirtual_h #define vtk_m_cont_ArrayHandleVirtual_h #include #include #include #include #include #include namespace vtkm { namespace cont { template class VTKM_ALWAYS_EXPORT ArrayHandleVirtual : public vtkm::cont::ArrayHandle { using StorageType = vtkm::cont::internal::Storage; public: VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleVirtual, (ArrayHandleVirtual), (vtkm::cont::ArrayHandle)); ///Construct a valid ArrayHandleVirtual from an existing ArrayHandle ///that doesn't derive from ArrayHandleVirtual. ///Note left non-explicit to allow: /// /// std::vector> vectorOfArrays; /// //Make basic array. /// vtkm::cont::ArrayHandle basicArray; /// //Fill basicArray... /// vectorOfArrays.push_back(basicArray); /// /// // Make fancy array. /// vtkm::cont::ArrayHandleCounting fancyArray(-1.0, 0.1, ARRAY_SIZE); /// vectorOfArrays.push_back(fancyArray); template ArrayHandleVirtual(const vtkm::cont::ArrayHandle& ah) : Superclass(StorageType(ah)) { using is_base = std::is_base_of; static_assert(!is_base::value, "Wrong specialization for ArrayHandleVirtual selected"); } /// Returns true if this array matches the type passed in. /// template VTKM_CONT bool IsType() const { VTKM_IS_ARRAY_HANDLE(ArrayHandleType); //We need to determine if we are checking that `ArrayHandleType` //is a virtual array handle since that is an easy check. //Or if we have to go ask the storage if they are holding // using ST = typename ArrayHandleType::StorageTag; using is_base = std::is_same; //Determine if the Value type of the virtual and ArrayHandleType //are the same. This an easy compile time check, and doesn't need // to be done at runtime. using VT = typename ArrayHandleType::ValueType; using same_value_type = std::is_same; return this->IsSameType(same_value_type{}, is_base{}); } /// Returns this array cast to the given \c ArrayHandle type. Throws \c /// ErrorBadType if the cast does not work. Use \c IsType /// to check if the cast can happen. /// template VTKM_CONT ArrayHandleType Cast() const { VTKM_IS_ARRAY_HANDLE(ArrayHandleType); //We need to determine if we are checking that `ArrayHandleType` //is a virtual array handle since that is an easy check. //Or if we have to go ask the storage if they are holding // using ST = typename ArrayHandleType::StorageTag; using is_base = std::is_same; //Determine if the Value type of the virtual and ArrayHandleType //are the same. This an easy compile time check, and doesn't need // to be done at runtime. using VT = typename ArrayHandleType::ValueType; using same_value_type = std::is_same; return this->CastToType(same_value_type{}, is_base{}); } /// Returns a new instance of an ArrayHandleVirtual with the same storage /// VTKM_CONT ArrayHandleVirtual NewInstance() const { return ArrayHandleVirtual(this->GetStorage().NewInstance()); } private: template inline bool IsSameType(std::false_type, std::true_type) const { return false; } template inline bool IsSameType(std::false_type, std::false_type) const { return false; } template inline bool IsSameType(std::true_type vtkmNotUsed(valueTypesMatch), std::true_type vtkmNotUsed(inheritsFromArrayHandleVirtual)) const { //The type being past has no requirements in being the most derived type //so the typeid info won't match but dynamic_cast will work auto casted = dynamic_cast(this); return casted != nullptr; } template inline bool IsSameType(std::true_type vtkmNotUsed(valueTypesMatch), std::false_type vtkmNotUsed(notFromArrayHandleVirtual)) const { auto* storage = this->GetStorage().GetStorageVirtual(); if (!storage) { return false; } using S = typename ArrayHandleType::StorageTag; return storage->template IsType>(); } template inline ArrayHandleType CastToType(std::false_type vtkmNotUsed(valueTypesMatch), std::true_type vtkmNotUsed(notFromArrayHandleVirtual)) const { VTKM_LOG_CAST_FAIL(*this, ArrayHandleType); throwFailedDynamicCast("ArrayHandleVirtual", vtkm::cont::TypeToString()); return ArrayHandleType{}; } template inline ArrayHandleType CastToType(std::false_type vtkmNotUsed(valueTypesMatch), std::false_type vtkmNotUsed(notFromArrayHandleVirtual)) const { VTKM_LOG_CAST_FAIL(*this, ArrayHandleType); throwFailedDynamicCast("ArrayHandleVirtual", vtkm::cont::TypeToString()); return ArrayHandleType{}; } template inline ArrayHandleType CastToType( std::true_type vtkmNotUsed(valueTypesMatch), std::true_type vtkmNotUsed(inheritsFromArrayHandleVirtual)) const { //The type being passed has no requirements in being the most derived type //so the typeid info won't match but dynamic_cast will work const ArrayHandleType* derived = dynamic_cast(this); if (!derived) { VTKM_LOG_CAST_FAIL(*this, ArrayHandleType); throwFailedDynamicCast("ArrayHandleVirtual", vtkm::cont::TypeToString()); } VTKM_LOG_CAST_SUCC(*this, derived); return *derived; } template ArrayHandleType CastToType(std::true_type vtkmNotUsed(valueTypesMatch), std::false_type vtkmNotUsed(notFromArrayHandleVirtual)) const; }; //============================================================================= /// A convenience function for creating an ArrayHandleVirtual. template VTKM_CONT vtkm::cont::ArrayHandleVirtual make_ArrayHandleVirtual( const vtkm::cont::ArrayHandle& ah) { return vtkm::cont::ArrayHandleVirtual(ah); } //============================================================================= // Free function casting helpers /// Returns true if \c virtHandle matches the type of ArrayHandleType. /// template VTKM_CONT inline bool IsType( const vtkm::cont::ArrayHandle& virtHandle) { return static_cast>(virtHandle) .template IsType(); } /// Returns \c virtHandle cast to the given \c ArrayHandle type. Throws \c /// ErrorBadType if the cast does not work. Use \c IsType /// to check if the cast can happen. /// template VTKM_CONT inline ArrayHandleType Cast( const vtkm::cont::ArrayHandle& virtHandle) { return static_cast>(virtHandle) .template Cast(); } //============================================================================= // Specializations of serialization related classes /// @cond SERIALIZATION template struct SerializableTypeString> { static VTKM_CONT const std::string& Get() { static std::string name = "AH_Virtual<" + SerializableTypeString::Get() + ">"; return name; } }; template struct SerializableTypeString> : public SerializableTypeString> { }; #ifndef vtk_m_cont_ArrayHandleVirtual_cxx #define VTK_M_ARRAY_HANDLE_VIRTUAL_EXPORT(T) \ extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle; \ extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleVirtual; \ extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle, StorageTagVirtual>; \ extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleVirtual>; \ extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle, StorageTagVirtual>; \ extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleVirtual>; \ extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle, StorageTagVirtual>; \ extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleVirtual> VTK_M_ARRAY_HANDLE_VIRTUAL_EXPORT(char); VTK_M_ARRAY_HANDLE_VIRTUAL_EXPORT(vtkm::Int8); VTK_M_ARRAY_HANDLE_VIRTUAL_EXPORT(vtkm::UInt8); VTK_M_ARRAY_HANDLE_VIRTUAL_EXPORT(vtkm::Int16); VTK_M_ARRAY_HANDLE_VIRTUAL_EXPORT(vtkm::UInt16); VTK_M_ARRAY_HANDLE_VIRTUAL_EXPORT(vtkm::Int32); VTK_M_ARRAY_HANDLE_VIRTUAL_EXPORT(vtkm::UInt32); VTK_M_ARRAY_HANDLE_VIRTUAL_EXPORT(vtkm::Int64); VTK_M_ARRAY_HANDLE_VIRTUAL_EXPORT(vtkm::UInt64); VTK_M_ARRAY_HANDLE_VIRTUAL_EXPORT(vtkm::Float32); VTK_M_ARRAY_HANDLE_VIRTUAL_EXPORT(vtkm::Float64); #undef VTK_M_ARRAY_HANDLE_VIRTUAL_EXPORT #endif //vtk_m_cont_ArrayHandleVirtual_cxx } } //namespace vtkm::cont /// @endcond SERIALIZATION #endif //vtk_m_cont_ArrayHandleVirtual_h