//============================================================================ // 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. // // Copyright 2018 National Technology & Engineering Solutions of Sandia, LLC (NTESS). // Copyright 2018 UT-Battelle, LLC. // Copyright 2018 Los Alamos National Security. // // Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National // Laboratory (LANL), the U.S. Government retains certain rights in // this software. //============================================================================ #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::ArrayHandleVirtual& virtHandle) { return 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::ArrayHandleVirtual& virtHandle) { return virtHandle.template Cast(); } #if 0 // The following specialization of CastAndCall has been disabled. The problem with it is that it // causes some common versions of GCC to give the warning "type attributes ignored after type is // already defined." GCC seems to have a problem with declaring an instance of a template twice // even when the type attributes match. (In some cases it is OK, in others it is not.) The easiest // solution is to just disable this CastAndCall that instantiates a specific version of // ArrayHandleVirtual. This specialization might be better handled elsewhere where the uniform // point coordinates are coupled with a structured cell set (and thus can derive several fast // paths) rather than generally for any field or array containing vec3s. //============================================================================= // Specializations of CastAndCall to help make sure ArrayHandleVirtual // holding a ArrayHandleUniformPointCoordinates works properly template void CastAndCall(vtkm::cont::ArrayHandleVirtual> coords, Functor&& f, Args&&... args) { using HandleType = ArrayHandleUniformPointCoordinates; using T = typename HandleType::ValueType; using S = typename HandleType::StorageTag; if (coords.IsType()) { const vtkm::cont::internal::detail::StorageVirtual* storage = coords.GetStorage().GetStorageVirtual(); auto* virtualImpl = storage->Cast>(); f(virtualImpl->GetHandle(), std::forward(args)...); } else { f(coords, std::forward(args)...); } } #endif //============================================================================= // Specializations of serialization related classes template struct SerializableTypeString> { static VTKM_CONT const std::string& Get() { static std::string name = "AH_Virtual<" + SerializableTypeString::Get() + ">"; return name; } }; #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 #endif //vtk_m_cont_ArrayHandleVirtual_h