//============================================================================ // 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_VariantArrayHandle_h #define vtk_m_cont_VariantArrayHandle_h #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef VTKM_NO_DEPRECATED_VIRTUAL #include #endif //VTKM_NO_DEPRECATED_VIRTUAL // This is a deprecated class. Don't warn about deprecation while implementing // deprecated functionality. VTKM_DEPRECATED_SUPPRESS_BEGIN namespace vtkm { namespace cont { #ifndef VTKM_NO_DEPRECATED_VIRTUAL namespace internal { namespace variant { struct ForceCastToVirtual { template VTKM_CONT typename std::enable_if::value>::type operator()(const vtkm::cont::ArrayHandle& input, vtkm::cont::ArrayHandleVirtual& output) const { // ValueTypes match output = vtkm::cont::make_ArrayHandleVirtual(input); } template VTKM_CONT typename std::enable_if::value>::type operator()(const vtkm::cont::ArrayHandle& input, vtkm::cont::ArrayHandleVirtual& output) const { // ValueTypes do not match this->ValidateWidthAndCast(input, output); } private: template ::NUM_COMPONENTS, vtkm::IdComponent DSize = vtkm::VecTraits::NUM_COMPONENTS> VTKM_CONT typename std::enable_if::type ValidateWidthAndCast( const InputType& input, vtkm::cont::ArrayHandleVirtual& output) const { // number of components match auto casted = vtkm::cont::make_ArrayHandleCast(input); output = vtkm::cont::make_ArrayHandleVirtual(casted); } template ::NUM_COMPONENTS, vtkm::IdComponent DSize = vtkm::VecTraits::NUM_COMPONENTS> VTKM_CONT typename std::enable_if::type ValidateWidthAndCast( const ArrayHandleBase&, ArrayHandleBase&) const { // number of components do not match std::ostringstream str; str << "VariantArrayHandle::AsVirtual: Cannot cast from " << vtkm::cont::TypeToString() << " to " << vtkm::cont::TypeToString() << "; " "number of components must match exactly."; throw vtkm::cont::ErrorBadType(str.str()); } }; template struct NoCastStorageTransformImpl { using type = S; }; template struct NoCastStorageTransformImpl> { using type = S; }; template using NoCastStorageTransform = typename NoCastStorageTransformImpl::type; } } // namespace internal::variant #endif //VTKM_NO_DEPRECATED_VIRTUAL /// \brief VariantArrayHandle superclass holding common operations. /// /// `VariantArrayHandleCommon` is a superclass to all `VariantArrayHandleBase` /// and `VariantArrayHandle` classes. It contains all operations that are /// independent of the type lists defined for these templated class or has /// versions of methods that allow you to specify type lists. /// /// See the documentation of `VariantArrayHandleBase` for more information. /// class VTKM_ALWAYS_EXPORT VTKM_DEPRECATED( 1.7, "VariantArrayHandle classes replaced with UnknownArrayHandle and UncertainArrayHandle.") VariantArrayHandleCommon : public vtkm::cont::UnknownArrayHandle { using Superclass = vtkm::cont::UnknownArrayHandle; public: using Superclass::Superclass; VTKM_CONT VariantArrayHandleCommon() = default; VTKM_CONT VariantArrayHandleCommon(const vtkm::cont::UnknownArrayHandle& array) : Superclass(array) { } /// 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 { return this->AsArrayHandle(); } /// \brief Call a functor using the underlying array type. /// /// `CastAndCall` attempts to cast the held array to a specific value type, /// and then calls the given functor with the cast array. You must specify /// the `TypeList` and `StorageList` as template arguments. (Note that this /// calling differs from that of the `CastAndCall` methods of subclasses.) /// template VTKM_CONT void CastAndCall(Functor&& functor, Args&&... args) const { this->CastAndCallForTypes(std::forward(functor), std::forward(args)...); } #ifndef VTKM_NO_DEPRECATED_VIRTUAL /// Returns this array cast to a `ArrayHandleVirtual` of the given type. /// This will perform type conversions as necessary, and will log warnings /// if the conversion is lossy. /// /// This method internally uses `CastAndCall`. A custom storage tag list may /// be specified in the second template parameter, which will be passed to /// the CastAndCall. You can also specify a list of types to try as the optional /// third template argument. /// template > VTKM_CONT VTKM_DEPRECATED(1.6, "ArrayHandleVirtual is no longer supported.") vtkm::cont::ArrayHandleVirtual AsVirtual() const { VTKM_IS_LIST(StorageList); VTKM_IS_LIST(TypeList); // Remove cast storage from storage list because we take care of casting elsewhere using CleanStorageList = vtkm::ListTransform; vtkm::cont::internal::variant::ForceCastToVirtual caster; vtkm::cont::ArrayHandleVirtual output; this->CastAndCall(caster, output); return output; } #endif //VTKM_NO_DEPRECATED_VIRTUAL /// Returns this array cast to a `ArrayHandleMultiplexer` of the given type. /// This will attempt to cast the internal array to each supported type of /// the multiplexer. If none are supported, an invalid ArrayHandleMultiplexer /// is returned. /// /// As a special case, if one of the arrays in the `ArrayHandleMultiplexer`'s /// type list is an `ArrayHandleCast`, then the multiplexer will look for type /// type of array being cast rather than an actual cast array. /// ///@{ template VTKM_CONT void AsMultiplexer(vtkm::cont::ArrayHandleMultiplexer& result) const { this->AsArrayHandle(result); } template VTKM_CONT ArrayHandleMultiplexerType AsMultiplexer() const { ArrayHandleMultiplexerType result; this->AsMultiplexer(result); return result; } ///@} /// Given a references to an ArrayHandle object, casts this array to the /// ArrayHandle's type and sets the given ArrayHandle to this array. Throws /// `ErrorBadType` if the cast does not work. Use `IsType` to check /// if the cast can happen. /// /// Note that this is a shallow copy. The data are not copied and a change /// in the data in one array will be reflected in the other. /// template VTKM_CONT void CopyTo(ArrayHandleType& array) const { VTKM_IS_ARRAY_HANDLE(ArrayHandleType); array = this->Cast(); } /// \brief Create a new array of the same type as this array. /// /// This method creates a new array that is the same type as this one and /// returns a new variant array handle for it. This method is convenient when /// creating output arrays that should be the same type as some input array. /// VTKM_CONT VariantArrayHandleCommon NewInstance() const { return VariantArrayHandleCommon(this->Superclass::NewInstance()); } }; /// \brief Holds an array handle without having to specify template parameters. /// /// `VariantArrayHandle` holds an `ArrayHandle` /// object using runtime polymorphism to manage different value types and /// storage rather than compile-time templates. This adds a programming /// convenience that helps avoid a proliferation of templates. It also provides /// the management necessary to interface VTK-m with data sources where types /// will not be known until runtime. /// /// To interface between the runtime polymorphism and the templated algorithms /// in VTK-m, `VariantArrayHandle` contains a method named `CastAndCall` that /// will determine the correct type from some known list of types. /// This mechanism is used internally by VTK-m's worklet invocation /// mechanism to determine the type when running algorithms. /// /// By default, `VariantArrayHandle` will assume that the value type in the /// array matches one of the types specified by `VTKM_DEFAULT_TYPE_LIST` /// This list can be changed by using the `ResetTypes`. It is /// worthwhile to match these lists closely to the possible types that might be /// used. If a type is missing you will get a runtime error. If there are more /// types than necessary, then the template mechanism will create a lot of /// object code that is never used, and keep in mind that the number of /// combinations grows exponentially when using multiple `VariantArrayHandle` /// objects. /// /// The actual implementation of `VariantArrayHandle` is in a templated class /// named `VariantArrayHandleBase`, which is templated on the list of /// component types. /// template class VTKM_ALWAYS_EXPORT VTKM_DEPRECATED( 1.7, "VariantArrayHandle classes replaced with UnknownArrayHandle and UncertainArrayHandle.") VariantArrayHandleBase : public VariantArrayHandleCommon { VTKM_STATIC_ASSERT_MSG((!std::is_same::value), "Cannot use vtkm::ListUniversal with VariantArrayHandle."); using Superclass = VariantArrayHandleCommon; public: VTKM_CONT VariantArrayHandleBase() = default; template VTKM_CONT VariantArrayHandleBase(const vtkm::cont::ArrayHandle& array) : Superclass(array) { } VTKM_CONT explicit VariantArrayHandleBase(const VariantArrayHandleCommon& src) : Superclass(src) { } VTKM_CONT VariantArrayHandleBase(const vtkm::cont::UnknownArrayHandle& src) : Superclass(src) { } VTKM_CONT VariantArrayHandleBase(const VariantArrayHandleBase&) = default; VTKM_CONT VariantArrayHandleBase(VariantArrayHandleBase&&) noexcept = default; VTKM_CONT ~VariantArrayHandleBase() {} VTKM_CONT VariantArrayHandleBase& operator=(const VariantArrayHandleBase&) = default; VTKM_CONT VariantArrayHandleBase& operator=(VariantArrayHandleBase&&) noexcept = default; VTKM_CONT operator vtkm::cont::UncertainArrayHandle() const { return vtkm::cont::UncertainArrayHandle(*this); } #ifndef VTKM_NO_DEPRECATED_VIRTUAL /// Returns this array cast to a \c ArrayHandleVirtual of the given type. /// This will perform type conversions as necessary, and will log warnings /// if the conversion is lossy. /// /// This method internally uses CastAndCall. A custom storage tag list may /// be specified in the second template parameter, which will be passed to /// the CastAndCall. /// template VTKM_CONT VTKM_DEPRECATED(1.6, "ArrayHandleVirtual is no longer suported.") vtkm::cont::ArrayHandleVirtual AsVirtual() const { return this->Superclass::AsVirtual(); } #endif //VTKM_NO_DEPRECATED_VIRTUAL /// Changes the types to try casting to when resolving this variant array, /// which is specified with a list tag like those in TypeList.h. Since C++ /// does not allow you to actually change the template arguments, this method /// returns a new variant array object. This method is particularly useful to /// narrow down (or expand) the types when using an array of particular /// constraints. /// template VTKM_CONT VariantArrayHandleBase ResetTypes(NewTypeList = NewTypeList()) const { VTKM_IS_LIST(NewTypeList); return VariantArrayHandleBase(*this); } //@{ /// \brief Call a functor using the underlying array type. /// /// `CastAndCall` attempts to cast the held array to a specific value type, /// then call the given functor with the cast array. The types /// tried in the cast are those in the lists defined by the TypeList. /// By default `VariantArrayHandle` set this to `VTKM_DEFAULT_TYPE_LIST`. /// /// In addition to the value type, an `ArrayHandle` also requires a storage tag. /// By default, `CastAndCall` attempts to cast the array using the storage tags /// listed in `VTKM_DEFAULT_STORAGE_LIST`. You can optionally give a custom /// list of storage tags as the second argument. /// /// As previous stated, if a storage tag list is provided, it is given in the /// first argument. The functor to call with the cast array is given as the next /// argument (or the first argument if a storage tag list is not provided). /// The remaning arguments, if any, are passed to the functor. /// /// The functor will be called with the cast array as its first argument. Any /// remaining arguments are passed from the arguments to `CastAndCall`. /// template VTKM_CONT void CastAndCall(FunctorOrStorageList&& functorOrStorageList, Args&&... args) const { this->CastAndCallImpl(vtkm::internal::IsList(), std::forward(functorOrStorageList), std::forward(args)...); } template VTKM_CONT void CastAndCall(Functor&& f) const { this->CastAndCallImpl(std::false_type(), std::forward(f)); } //@} /// \brief Create a new array of the same type as this array. /// /// This method creates a new array that is the same type as this one and /// returns a new variant array handle for it. This method is convenient when /// creating output arrays that should be the same type as some input array. /// VTKM_CONT VariantArrayHandleBase NewInstance() const { return VariantArrayHandleBase(this->Superclass::NewInstance()); } private: template VTKM_CONT void CastAndCallImpl(std::false_type, Functor&& f, Args&&... args) const { this->Superclass::CastAndCall(std::forward(f), std::forward(args)...); } template VTKM_CONT void CastAndCallImpl(std::true_type, StorageList, Functor&& f, Args&&... args) const { this->Superclass::CastAndCall(std::forward(f), std::forward(args)...); } }; using VariantArrayHandle VTKM_DEPRECATED( 1.7, "VariantArrayHandle classes replaced with UnknownArrayHandle and UncertainArrayHandle.") = vtkm::cont::VariantArrayHandleBase; //============================================================================= // Free function casting helpers /// Returns true if \c variant matches the type of ArrayHandleType. /// template VTKM_CONT inline bool IsType(const vtkm::cont::VariantArrayHandleBase& variant) { return variant.template IsType(); } /// Returns \c variant 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::VariantArrayHandleBase& variant) { return variant.template Cast(); } namespace internal { template struct DynamicTransformTraits> { using DynamicTag = vtkm::cont::internal::DynamicTransformTagCastAndCall; }; } // namespace internal } // namespace cont } // namespace vtkm //============================================================================= // Specializations of serialization related classes /// @cond SERIALIZATION namespace mangled_diy_namespace { template struct Serialization> { private: using Type = vtkm::cont::VariantArrayHandleBase; using ImplObject = vtkm::cont::UncertainArrayHandle; public: static VTKM_CONT void save(BinaryBuffer& bb, const Type& obj) { vtkmdiy::save(bb, ImplObject(obj)); } static VTKM_CONT void load(BinaryBuffer& bb, Type& obj) { ImplObject implObj; vtkmdiy::load(bb, implObj); obj = implObj; } }; } // diy /// @endcond SERIALIZATION VTKM_DEPRECATED_SUPPRESS_END #endif //vtk_m_virts_VariantArrayHandle_h