Merge topic 'replace-variantarrayhandle-impl'

386301719 Test UnknownArrayHandle behavior on special arrays
872da1f8e Suppress unnecessary deprecation warnings on VS
bb443bbc2 Replace the implementation of VariantArrayHandle

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Robert Maynard <robert.maynard@kitware.com>
Merge-request: !2255
This commit is contained in:
Kenneth Moreland 2020-09-05 04:31:51 +00:00 committed by Kitware Robot
commit 06579aac8c
9 changed files with 220 additions and 726 deletions

@ -183,7 +183,6 @@ set(sources
DataSetBuilderExplicit.cxx DataSetBuilderExplicit.cxx
DataSetBuilderRectilinear.cxx DataSetBuilderRectilinear.cxx
DataSetBuilderUniform.cxx DataSetBuilderUniform.cxx
internal/VariantArrayHandleContainer.cxx
Field.cxx Field.cxx
FieldRangeCompute.cxx FieldRangeCompute.cxx
FieldRangeGlobalCompute.cxx FieldRangeGlobalCompute.cxx

@ -220,6 +220,7 @@ class VTKM_CONT_EXPORT UnknownArrayHandle
public: public:
VTKM_CONT UnknownArrayHandle() = default; VTKM_CONT UnknownArrayHandle() = default;
UnknownArrayHandle(const UnknownArrayHandle&) = default;
template <typename T, typename S> template <typename T, typename S>
VTKM_CONT UnknownArrayHandle(const vtkm::cont::ArrayHandle<T, S>& array) VTKM_CONT UnknownArrayHandle(const vtkm::cont::ArrayHandle<T, S>& array)
@ -227,6 +228,8 @@ public:
{ {
} }
UnknownArrayHandle& operator=(const vtkm::cont::UnknownArrayHandle&) = default;
/// \brief Create a new array of the same type as this array. /// \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 /// This method creates a new array that is the same type as this one and
@ -323,6 +326,14 @@ public:
template <typename ArrayHandleType> template <typename ArrayHandleType>
VTKM_CONT bool CanConvert() const; VTKM_CONT bool CanConvert() const;
// MSVC will issue deprecation warnings here if this template is instantiated with
// a deprecated class even if the template is used from a section of code where
// deprecation warnings are suppressed. This is annoying behavior since this template
// has no control over what class it is used with. To get around it, we have to
// suppress all deprecation warnings here.
#ifdef VTKM_MSVC
VTKM_DEPRECATED_SUPPRESS_BEGIN
#endif
///@{ ///@{
/// Returns this array cast appropriately and stored in the given `ArrayHandle` type. /// Returns this array cast appropriately and stored in the given `ArrayHandle` type.
/// Throws an `ErrorBadType` if the stored array cannot be stored in the given array type. /// Throws an `ErrorBadType` if the stored array cannot be stored in the given array type.
@ -363,6 +374,9 @@ public:
return array; return array;
} }
///@} ///@}
#ifdef VTKM_MSVC
VTKM_DEPRECATED_SUPPRESS_END
#endif
/// \brief Call a functor using the underlying array type. /// \brief Call a functor using the underlying array type.
/// ///
@ -476,8 +490,17 @@ struct UnknownArrayHandleMultplexerCastTry
bool& converted) const bool& converted) const
{ {
using ArrayType = vtkm::cont::ArrayHandle<T, S>; using ArrayType = vtkm::cont::ArrayHandle<T, S>;
if (!converted && unknownArray.CanConvert<ArrayType>()) if (unknownArray.CanConvert<ArrayType>())
{ {
if (converted && !unknownArray.IsType<ArrayType>())
{
// The array has already been converted and pushed in the multiplexer. It is
// possible that multiple array types can be put in the ArrayHandleMultiplexer
// (for example, and ArrayHandle or an ArrayHandle that has been cast). Exact
// matches will override other matches (hence, the second part of the condition),
// but at this point we have already found a better array to put inside.
return;
}
outputArray.GetStorage().SetArray(unknownArray.AsArrayHandle<ArrayType>()); outputArray.GetStorage().SetArray(unknownArray.AsArrayHandle<ArrayType>());
converted = true; converted = true;
} }

@ -23,14 +23,71 @@
#include <vtkm/cont/ErrorBadType.h> #include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/Logging.h> #include <vtkm/cont/Logging.h>
#include <vtkm/cont/StorageList.h> #include <vtkm/cont/StorageList.h>
#include <vtkm/cont/UncertainArrayHandle.h>
#include <vtkm/cont/internal/VariantArrayHandleContainer.h> #include <vtkm/cont/UnknownArrayHandle.h>
namespace vtkm namespace vtkm
{ {
namespace cont namespace cont
{ {
namespace internal
{
namespace variant
{
struct ForceCastToVirtual
{
template <typename SrcValueType, typename Storage, typename DstValueType>
VTKM_CONT typename std::enable_if<std::is_same<SrcValueType, DstValueType>::value>::type
operator()(const vtkm::cont::ArrayHandle<SrcValueType, Storage>& input,
vtkm::cont::ArrayHandleVirtual<DstValueType>& output) const
{ // ValueTypes match
output = vtkm::cont::make_ArrayHandleVirtual<DstValueType>(input);
}
template <typename SrcValueType, typename Storage, typename DstValueType>
VTKM_CONT typename std::enable_if<!std::is_same<SrcValueType, DstValueType>::value>::type
operator()(const vtkm::cont::ArrayHandle<SrcValueType, Storage>& input,
vtkm::cont::ArrayHandleVirtual<DstValueType>& output) const
{ // ValueTypes do not match
this->ValidateWidthAndCast<SrcValueType, DstValueType>(input, output);
}
private:
template <typename S,
typename D,
typename InputType,
vtkm::IdComponent SSize = vtkm::VecTraits<S>::NUM_COMPONENTS,
vtkm::IdComponent DSize = vtkm::VecTraits<D>::NUM_COMPONENTS>
VTKM_CONT typename std::enable_if<SSize == DSize>::type ValidateWidthAndCast(
const InputType& input,
vtkm::cont::ArrayHandleVirtual<D>& output) const
{ // number of components match
auto casted = vtkm::cont::make_ArrayHandleCast<D>(input);
output = vtkm::cont::make_ArrayHandleVirtual<D>(casted);
}
template <typename S,
typename D,
vtkm::IdComponent SSize = vtkm::VecTraits<S>::NUM_COMPONENTS,
vtkm::IdComponent DSize = vtkm::VecTraits<D>::NUM_COMPONENTS>
VTKM_CONT typename std::enable_if<SSize != DSize>::type ValidateWidthAndCast(
const ArrayHandleBase&,
ArrayHandleBase&) const
{ // number of components do not match
std::ostringstream str;
str << "VariantArrayHandle::AsVirtual: Cannot cast from " << vtkm::cont::TypeToString<S>()
<< " to " << vtkm::cont::TypeToString<D>()
<< "; "
"number of components must match exactly.";
throw vtkm::cont::ErrorBadType(str.str());
}
};
}
} // namespace internal::variant
/// \brief VariantArrayHandle superclass holding common operations. /// \brief VariantArrayHandle superclass holding common operations.
/// ///
/// `VariantArrayHandleCommon` is a superclass to all `VariantArrayHandleBase` /// `VariantArrayHandleCommon` is a superclass to all `VariantArrayHandleBase`
@ -40,43 +97,28 @@ namespace cont
/// ///
/// See the documentation of `VariantArrayHandleBase` for more information. /// See the documentation of `VariantArrayHandleBase` for more information.
/// ///
class VTKM_ALWAYS_EXPORT VariantArrayHandleCommon class VTKM_ALWAYS_EXPORT VariantArrayHandleCommon : public vtkm::cont::UnknownArrayHandle
{ {
std::shared_ptr<vtkm::cont::internal::VariantArrayHandleContainerBase> ArrayContainer; using Superclass = vtkm::cont::UnknownArrayHandle;
public: public:
using Superclass::Superclass;
VTKM_CONT VariantArrayHandleCommon() = default; VTKM_CONT VariantArrayHandleCommon() = default;
template <typename T, typename Storage> VTKM_CONT VariantArrayHandleCommon(const vtkm::cont::UnknownArrayHandle& array)
VTKM_CONT VariantArrayHandleCommon(const vtkm::cont::ArrayHandle<T, Storage>& array) : Superclass(array)
: ArrayContainer(std::make_shared<internal::VariantArrayHandleContainer<T>>(
vtkm::cont::ArrayHandleVirtual<T>{ array }))
{ {
} }
template <typename T> // MSVC will issue deprecation warnings here if this template is instantiated with
VTKM_CONT VariantArrayHandleCommon( // a deprecated class even if the template is used from a section of code where
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagVirtual>& array) // deprecation warnings are suppressed. This is annoying behavior since this template
: ArrayContainer(std::make_shared<internal::VariantArrayHandleContainer<T>>(array)) // has no control over what class it is used with. To get around it, we have to
{ // suppress all deprecation warnings here.
} #ifdef VTKM_MSVC
VTKM_DEPRECATED_SUPPRESS_BEGIN
/// Returns true if this array matches the array handle type passed in. #endif
///
template <typename ArrayHandleType>
VTKM_CONT bool IsType() const
{
return internal::variant::IsType<ArrayHandleType>(this->ArrayContainer.get());
}
/// Returns true if this array matches the ValueType type passed in.
///
template <typename T>
VTKM_CONT bool IsValueType() const
{
return internal::variant::IsValueType<T>(this->ArrayContainer.get());
}
/// Returns this array cast to the given \c ArrayHandle type. Throws \c /// Returns this array cast to the given \c ArrayHandle type. Throws \c
/// ErrorBadType if the cast does not work. Use \c IsType /// ErrorBadType if the cast does not work. Use \c IsType
/// to check if the cast can happen. /// to check if the cast can happen.
@ -84,19 +126,11 @@ public:
template <typename ArrayHandleType> template <typename ArrayHandleType>
VTKM_CONT ArrayHandleType Cast() const VTKM_CONT ArrayHandleType Cast() const
{ {
// MSVC will issue deprecation warnings if this templated method is instantiated with return this->AsArrayHandle<ArrayHandleType>();
// a deprecated class here even if the method is called from a section of code where
// deprecation warnings are suppressed. This is annoying behavior since this templated
// method has no control over what class it is used from. To get around it, we have to
// suppress all deprecation warnings here.
#ifdef VTKM_MSVC
VTKM_DEPRECATED_SUPPRESS_BEGIN
#endif
return internal::variant::Cast<ArrayHandleType>(this->ArrayContainer.get());
#ifdef VTKM_MSVC
VTKM_DEPRECATED_SUPPRESS_END
#endif
} }
#ifdef VTKM_MSVC
VTKM_DEPRECATED_SUPPRESS_END
#endif
/// \brief Call a functor using the underlying array type. /// \brief Call a functor using the underlying array type.
/// ///
@ -106,7 +140,11 @@ public:
/// calling differs from that of the `CastAndCall` methods of subclasses.) /// calling differs from that of the `CastAndCall` methods of subclasses.)
/// ///
template <typename TypeList, typename StorageList, typename Functor, typename... Args> template <typename TypeList, typename StorageList, typename Functor, typename... Args>
VTKM_CONT void CastAndCall(Functor&& functor, Args&&... args) const; VTKM_CONT void CastAndCall(Functor&& functor, Args&&... args) const
{
this->CastAndCallForTypes<TypeList, StorageList>(std::forward<Functor>(functor),
std::forward<Args>(args)...);
}
/// Returns this array cast to a `ArrayHandleVirtual` of the given type. /// Returns this array cast to a `ArrayHandleVirtual` of the given type.
/// This will perform type conversions as necessary, and will log warnings /// This will perform type conversions as necessary, and will log warnings
@ -141,7 +179,10 @@ public:
/// ///
///@{ ///@{
template <typename... T> template <typename... T>
VTKM_CONT void AsMultiplexer(vtkm::cont::ArrayHandleMultiplexer<T...>& result) const; VTKM_CONT void AsMultiplexer(vtkm::cont::ArrayHandleMultiplexer<T...>& result) const
{
this->AsArrayHandle(result);
}
template <typename ArrayHandleMultiplexerType> template <typename ArrayHandleMultiplexerType>
VTKM_CONT ArrayHandleMultiplexerType AsMultiplexer() const VTKM_CONT ArrayHandleMultiplexerType AsMultiplexer() const
@ -175,40 +216,8 @@ public:
/// ///
VTKM_CONT VariantArrayHandleCommon NewInstance() const VTKM_CONT VariantArrayHandleCommon NewInstance() const
{ {
VariantArrayHandleCommon instance; return VariantArrayHandleCommon(this->Superclass::NewInstance());
instance.ArrayContainer = this->ArrayContainer->NewInstance();
return instance;
} }
/// Releases any resources being used in the execution environment (that are
/// not being shared by the control environment).
///
void ReleaseResourcesExecution() { return this->ArrayContainer->ReleaseResourcesExecution(); }
/// Releases all resources in both the control and execution environments.
///
void ReleaseResources() { return this->ArrayContainer->ReleaseResources(); }
/// \brief Get the number of components in each array value.
///
/// This method will query the array type for the number of components in
/// each value of the array. The number of components is determined by
/// the \c VecTraits::NUM_COMPONENTS trait class.
///
VTKM_CONT
vtkm::IdComponent GetNumberOfComponents() const
{
return this->ArrayContainer->GetNumberOfComponents();
}
/// \brief Get the number of values in the array.
///
VTKM_CONT
vtkm::Id GetNumberOfValues() const { return this->ArrayContainer->GetNumberOfValues(); }
VTKM_CONT
void PrintSummary(std::ostream& out) const { this->ArrayContainer->PrintSummary(out); }
}; };
/// \brief Holds an array handle without having to specify template parameters. /// \brief Holds an array handle without having to specify template parameters.
@ -263,6 +272,18 @@ public:
{ {
} }
VTKM_CONT explicit VariantArrayHandleBase(const vtkm::cont::UnknownArrayHandle& src)
: Superclass(src)
{
}
template <typename StorageList>
VTKM_CONT VariantArrayHandleBase(
const vtkm::cont::UncertainArrayHandle<TypeList, StorageList>& src)
: Superclass(src)
{
}
VTKM_CONT VariantArrayHandleBase(const VariantArrayHandleBase&) = default; VTKM_CONT VariantArrayHandleBase(const VariantArrayHandleBase&) = default;
VTKM_CONT VariantArrayHandleBase(VariantArrayHandleBase&&) noexcept = default; VTKM_CONT VariantArrayHandleBase(VariantArrayHandleBase&&) noexcept = default;
@ -276,6 +297,11 @@ public:
VariantArrayHandleBase<TypeList>& operator=(VariantArrayHandleBase<TypeList>&&) noexcept = VariantArrayHandleBase<TypeList>& operator=(VariantArrayHandleBase<TypeList>&&) noexcept =
default; default;
VTKM_CONT operator vtkm::cont::UncertainArrayHandle<TypeList, VTKM_DEFAULT_STORAGE_LIST>() const
{
return vtkm::cont::UncertainArrayHandle<TypeList, VTKM_DEFAULT_STORAGE_LIST>(*this);
}
/// Returns this array cast to a \c ArrayHandleVirtual of the given type. /// Returns this array cast to a \c ArrayHandleVirtual of the given type.
/// This will perform type conversions as necessary, and will log warnings /// This will perform type conversions as necessary, and will log warnings
@ -392,207 +418,6 @@ VTKM_CONT inline ArrayHandleType Cast(const vtkm::cont::VariantArrayHandleBase<T
return variant.template Cast<ArrayHandleType>(); return variant.template Cast<ArrayHandleType>();
} }
//=============================================================================
// Out of class implementations
namespace detail
{
struct VariantArrayHandleTry
{
template <typename T, typename Storage, typename Functor, typename... Args>
void operator()(vtkm::List<T, Storage>,
Functor&& f,
bool& called,
const vtkm::cont::internal::VariantArrayHandleContainerBase& container,
Args&&... args) const
{
using DerivedArrayType = vtkm::cont::ArrayHandle<T, Storage>;
if (!called && vtkm::cont::internal::variant::IsType<DerivedArrayType>(&container))
{
called = true;
const auto* derivedContainer =
static_cast<const vtkm::cont::internal::VariantArrayHandleContainer<T>*>(&container);
DerivedArrayType derivedArray = derivedContainer->Array.template Cast<DerivedArrayType>();
VTKM_LOG_CAST_SUCC(container, derivedArray);
// If you get a compile error here, it means that you have called CastAndCall for a
// vtkm::cont::VariantArrayHandle and the arguments of the functor do not match those
// being passed. This is often because it is calling the functor with an ArrayHandle
// type that was not expected. Either add overloads to the functor to accept all
// possible array types or constrain the types tried for the CastAndCall. Note that
// the functor will be called with an array of type vtkm::cont::ArrayHandle<T, S>.
// Directly using a subclass of ArrayHandle (e.g. vtkm::cont::ArrayHandleConstant<T>)
// might not work.
f(derivedArray, std::forward<Args>(args)...);
}
}
};
template <typename T>
struct IsUndefinedStorage
{
};
template <typename T, typename U>
struct IsUndefinedStorage<vtkm::List<T, U>> : vtkm::cont::internal::IsInvalidArrayHandle<T, U>
{
};
template <typename TypeList, typename StorageList>
using ListDynamicTypes =
vtkm::ListRemoveIf<vtkm::ListCross<TypeList, StorageList>, IsUndefinedStorage>;
} // namespace detail
template <typename TypeList, typename StorageTagList, typename Functor, typename... Args>
VTKM_CONT void VariantArrayHandleCommon::CastAndCall(Functor&& f, Args&&... args) const
{
using crossProduct = detail::ListDynamicTypes<TypeList, StorageTagList>;
bool called = false;
const auto& ref = *this->ArrayContainer;
vtkm::ListForEach(detail::VariantArrayHandleTry{},
crossProduct{},
std::forward<Functor>(f),
called,
ref,
std::forward<Args>(args)...);
if (!called)
{
// throw an exception
VTKM_LOG_CAST_FAIL(*this, TypeList);
detail::ThrowCastAndCallException(ref, typeid(TypeList));
}
}
namespace detail
{
struct VariantArrayHandleTryMultiplexer
{
template <typename T, typename Storage, typename... ArrayTypes>
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, Storage>&,
const vtkm::cont::VariantArrayHandleCommon& self,
vtkm::cont::ArrayHandleMultiplexer<ArrayTypes...>& result) const
{
vtkm::cont::ArrayHandle<T, Storage> targetArray;
bool foundArray = false;
this->FetchArray(targetArray, self, foundArray, result.IsValid());
if (foundArray)
{
result.SetArray(targetArray);
VTKM_LOG_CAST_SUCC(self, result);
}
}
private:
template <typename T, typename Storage>
VTKM_CONT void FetchArrayExact(vtkm::cont::ArrayHandle<T, Storage>& targetArray,
const vtkm::cont::VariantArrayHandleCommon& self,
bool& foundArray) const
{
using ArrayType = vtkm::cont::ArrayHandle<T, Storage>;
if (self.IsType<ArrayType>())
{
targetArray = self.Cast<ArrayType>();
foundArray = true;
}
else
{
foundArray = false;
}
}
template <typename T, typename Storage>
VTKM_CONT void FetchArray(vtkm::cont::ArrayHandle<T, Storage>& targetArray,
const vtkm::cont::VariantArrayHandleCommon& self,
bool& foundArray,
bool vtkmNotUsed(foundArrayInPreviousCall)) const
{
this->FetchArrayExact(targetArray, self, foundArray);
}
// Special condition for transformed arrays. Instead of pulling out the
// transform, pull out the array that is being transformed.
template <typename T, typename SrcArray, typename ForwardTransform, typename ReverseTransform>
VTKM_CONT void FetchArray(
vtkm::cont::ArrayHandle<
T,
vtkm::cont::internal::StorageTagTransform<SrcArray, ForwardTransform, ReverseTransform>>&
targetArray,
const vtkm::cont::VariantArrayHandleCommon& self,
bool& foundArray,
bool foundArrayInPreviousCall) const
{
// Attempt to get the array itself first
this->FetchArrayExact(targetArray, self, foundArray);
// Try to get the array to be transformed first, but only do so if the array was not already
// found in another call to this functor. This is to give precedence to getting the array
// exactly rather than creating our own transform.
if (!foundArray && !foundArrayInPreviousCall)
{
SrcArray srcArray;
this->FetchArray(srcArray, self, foundArray, foundArrayInPreviousCall);
if (foundArray)
{
targetArray =
vtkm::cont::ArrayHandleTransform<SrcArray, ForwardTransform, ReverseTransform>(srcArray);
}
}
}
// Special condition for cast arrays. Instead of pulling out an ArrayHandleCast, pull out
// the array that is being cast.
template <typename TargetT, typename SourceT, typename SourceStorage>
VTKM_CONT void FetchArray(
vtkm::cont::ArrayHandle<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceStorage>>&
targetArray,
const vtkm::cont::VariantArrayHandleCommon& self,
bool& foundArray,
bool foundArrayInPreviousCall) const
{
// Attempt to get the array itself first
this->FetchArrayExact(targetArray, self, foundArray);
// Try to get the array to be transformed first, but only do so if the array was not already
// found in another call to this functor. This is to give precedence to getting the array
// exactly rather than creating our own transform.
if (!foundArray && !foundArrayInPreviousCall)
{
using SrcArray = vtkm::cont::ArrayHandle<SourceT, SourceStorage>;
SrcArray srcArray;
this->FetchArray(srcArray, self, foundArray, foundArrayInPreviousCall);
if (foundArray)
{
targetArray =
vtkm::cont::ArrayHandleCast<TargetT, vtkm::cont::ArrayHandle<SourceT, SourceStorage>>(
srcArray);
}
}
}
};
} // namespace detail
template <typename... T>
inline VTKM_CONT void VariantArrayHandleCommon::AsMultiplexer(
vtkm::cont::ArrayHandleMultiplexer<T...>& result) const
{
// Make sure IsValid is clear
result = vtkm::cont::ArrayHandleMultiplexer<T...>{};
vtkm::ListForEach(detail::VariantArrayHandleTryMultiplexer{}, vtkm::List<T...>{}, *this, result);
if (!result.IsValid())
{
// Could not put the class into the multiplexer. Throw an exception.
VTKM_LOG_CAST_FAIL(*this, vtkm::List<T...>);
detail::ThrowAsMultiplexerException(*this->ArrayContainer, { typeid(T).name()... });
}
}
namespace internal namespace internal
{ {
@ -612,72 +437,24 @@ struct DynamicTransformTraits<vtkm::cont::VariantArrayHandleBase<TypeList>>
namespace mangled_diy_namespace namespace mangled_diy_namespace
{ {
namespace internal
{
struct VariantArrayHandleSerializeFunctor
{
template <typename ArrayHandleType>
void operator()(const ArrayHandleType& ah, BinaryBuffer& bb) const
{
vtkmdiy::save(bb, vtkm::cont::SerializableTypeString<ArrayHandleType>::Get());
vtkmdiy::save(bb, ah);
}
};
struct VariantArrayHandleDeserializeFunctor
{
template <typename T, typename S, typename TypeList>
void operator()(vtkm::List<T, S>,
vtkm::cont::VariantArrayHandleBase<TypeList>& dh,
const std::string& typeString,
bool& success,
BinaryBuffer& bb) const
{
using ArrayHandleType = vtkm::cont::ArrayHandle<T, S>;
if (!success && (typeString == vtkm::cont::SerializableTypeString<ArrayHandleType>::Get()))
{
ArrayHandleType ah;
vtkmdiy::load(bb, ah);
dh = vtkm::cont::VariantArrayHandleBase<TypeList>(ah);
success = true;
}
}
};
} // internal
template <typename TypeList> template <typename TypeList>
struct Serialization<vtkm::cont::VariantArrayHandleBase<TypeList>> struct Serialization<vtkm::cont::VariantArrayHandleBase<TypeList>>
{ {
private: private:
using Type = vtkm::cont::VariantArrayHandleBase<TypeList>; using Type = vtkm::cont::VariantArrayHandleBase<TypeList>;
using ImplObject = vtkm::cont::UncertainArrayHandle<TypeList, VTKM_DEFAULT_STORAGE_LIST>;
public: public:
static VTKM_CONT void save(BinaryBuffer& bb, const Type& obj) static VTKM_CONT void save(BinaryBuffer& bb, const Type& obj)
{ {
obj.CastAndCall(internal::VariantArrayHandleSerializeFunctor{}, bb); vtkmdiy::save(bb, ImplObject(obj));
} }
static VTKM_CONT void load(BinaryBuffer& bb, Type& obj) static VTKM_CONT void load(BinaryBuffer& bb, Type& obj)
{ {
std::string typeString; ImplObject implObj;
vtkmdiy::load(bb, typeString); vtkmdiy::load(bb, implObj);
obj = implObj;
bool success = false;
vtkm::ListForEach(internal::VariantArrayHandleDeserializeFunctor{},
vtkm::cont::detail::ListDynamicTypes<TypeList, VTKM_DEFAULT_STORAGE_LIST>{},
obj,
typeString,
success,
bb);
if (!success)
{
throw vtkm::cont::ErrorBadType(
"Error deserializing VariantArrayHandle. Message TypeString: " + typeString);
}
} }
}; };

@ -33,7 +33,6 @@ set(headers
ReverseConnectivityBuilder.h ReverseConnectivityBuilder.h
StorageError.h StorageError.h
TransferInfo.h TransferInfo.h
VariantArrayHandleContainer.h
VirtualObjectTransfer.h VirtualObjectTransfer.h
VirtualObjectTransferInstantiate.h VirtualObjectTransferInstantiate.h
VirtualObjectTransferShareWithControl.h VirtualObjectTransferShareWithControl.h

@ -1,68 +0,0 @@
//============================================================================
// 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.
//============================================================================
#include <sstream>
#include <typeindex>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/internal/VariantArrayHandleContainer.h>
namespace vtkm
{
namespace cont
{
namespace internal
{
VariantArrayHandleContainerBase::VariantArrayHandleContainerBase()
: TypeIndex(typeid(nullptr))
{
}
VariantArrayHandleContainerBase::VariantArrayHandleContainerBase(const std::type_info& typeinfo)
: TypeIndex(typeinfo)
{
}
VariantArrayHandleContainerBase::~VariantArrayHandleContainerBase() {}
}
namespace detail
{
VTKM_CONT_EXPORT void ThrowCastAndCallException(
const vtkm::cont::internal::VariantArrayHandleContainerBase& ref,
const std::type_info& type)
{
std::ostringstream out;
out << "Could not find appropriate cast for array in CastAndCall.\n"
"Array: ";
ref.PrintSummary(out);
out << "TypeList: " << type.name() << "\n";
throw vtkm::cont::ErrorBadValue(out.str());
}
VTKM_CONT_EXPORT void ThrowAsMultiplexerException(
const vtkm::cont::internal::VariantArrayHandleContainerBase& ref,
const std::initializer_list<std::string>& arrayTypes)
{
std::ostringstream out;
out << "Could not find appropriate cast for array in AsMultiplexer.\n"
"Array: ";
ref.PrintSummary(out);
out << "Supported arrays:\n";
for (auto&& type : arrayTypes)
{
out << " " << type << "\n";
}
throw vtkm::cont::ErrorBadValue(out.str());
}
}
}
} // namespace vtkm::cont::detail

@ -1,301 +0,0 @@
//============================================================================
// 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_VariantArrayHandleContainer_h
#define vtk_m_cont_VariantArrayHandleContainer_h
#include <vtkm/cont/vtkm_cont_export.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleVirtual.h>
#include <vtkm/cont/ArrayHandleVirtual.hxx>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/VecTraits.h>
#include <memory>
#include <sstream>
#include <typeindex>
namespace vtkm
{
namespace cont
{
// Forward declaration needed for GetContainer
template <typename TypeList>
class VariantArrayHandleBase;
namespace internal
{
/// \brief Base class for VariantArrayHandleContainer
///
struct VTKM_CONT_EXPORT VariantArrayHandleContainerBase
{
std::type_index TypeIndex;
VariantArrayHandleContainerBase();
explicit VariantArrayHandleContainerBase(const std::type_info& hash);
// This must exist so that subclasses are destroyed correctly.
virtual ~VariantArrayHandleContainerBase();
virtual vtkm::Id GetNumberOfValues() const = 0;
virtual vtkm::IdComponent GetNumberOfComponents() const = 0;
virtual void ReleaseResourcesExecution() = 0;
virtual void ReleaseResources() = 0;
virtual void PrintSummary(std::ostream& out) const = 0;
virtual std::shared_ptr<VariantArrayHandleContainerBase> NewInstance() const = 0;
};
/// \brief ArrayHandle container that can use C++ run-time type information.
///
/// The \c VariantArrayHandleContainer holds ArrayHandle objects
/// (with different template parameters) so that it can polymorphically answer
/// simple questions about the object.
///
template <typename T>
struct VTKM_ALWAYS_EXPORT VariantArrayHandleContainer final : public VariantArrayHandleContainerBase
{
vtkm::cont::ArrayHandleVirtual<T> Array;
mutable vtkm::IdComponent NumberOfComponents = 0;
VariantArrayHandleContainer()
: VariantArrayHandleContainerBase(typeid(T))
, Array()
{
}
VariantArrayHandleContainer(const vtkm::cont::ArrayHandleVirtual<T>& array)
: VariantArrayHandleContainerBase(typeid(T))
, Array(array)
{
}
~VariantArrayHandleContainer<T>() override = default;
vtkm::Id GetNumberOfValues() const override { return this->Array.GetNumberOfValues(); }
vtkm::IdComponent GetNumberOfComponents() const override
{
// Cache number of components to avoid unnecessary device to host transfers of the array.
// Also assumes that the number of components is constant accross all elements and
// throughout the life of the array.
if (this->NumberOfComponents == 0)
{
this->NumberOfComponents =
this->GetNumberOfComponents(typename vtkm::VecTraits<T>::IsSizeStatic{});
}
return this->NumberOfComponents;
}
void ReleaseResourcesExecution() override { this->Array.ReleaseResourcesExecution(); }
void ReleaseResources() override { this->Array.ReleaseResources(); }
void PrintSummary(std::ostream& out) const override
{
vtkm::cont::printSummary_ArrayHandle(this->Array, out);
}
std::shared_ptr<VariantArrayHandleContainerBase> NewInstance() const override
{
return std::make_shared<VariantArrayHandleContainer<T>>(this->Array.NewInstance());
}
private:
vtkm::IdComponent GetNumberOfComponents(VecTraitsTagSizeStatic) const
{
return vtkm::VecTraits<T>::NUM_COMPONENTS;
}
vtkm::IdComponent GetNumberOfComponents(VecTraitsTagSizeVariable) const
{
return (this->Array.GetNumberOfValues() == 0)
? 0
: vtkm::VecTraits<T>::GetNumberOfComponents(this->Array.ReadPortal().Get(0));
}
};
namespace variant
{
// One instance of a template class cannot access the private members of
// another instance of a template class. However, I want to be able to copy
// construct a VariantArrayHandle from another VariantArrayHandle of any other
// type. Since you cannot partially specialize friendship, use this accessor
// class to get at the internals for the copy constructor.
struct GetContainer
{
template <typename TypeList>
VTKM_CONT static const std::shared_ptr<VariantArrayHandleContainerBase>& Extract(
const vtkm::cont::VariantArrayHandleBase<TypeList>& src)
{
return src.ArrayContainer;
}
};
template <typename T>
VTKM_CONT bool IsValueType(const VariantArrayHandleContainerBase* container)
{
if (container == nullptr)
{ //you can't use typeid on nullptr of polymorphic types
return false;
}
//needs optimizations based on platform. !OSX can use typeid
return container->TypeIndex == std::type_index(typeid(T));
// return (nullptr != dynamic_cast<const VariantArrayHandleContainer<T>*>(container));
}
template <typename ArrayHandleType>
VTKM_CONT inline bool IsType(const VariantArrayHandleContainerBase* container)
{ //container could be nullptr
using T = typename ArrayHandleType::ValueType;
if (!IsValueType<T>(container))
{
return false;
}
const auto* derived = static_cast<const VariantArrayHandleContainer<T>*>(container);
return vtkm::cont::IsType<ArrayHandleType>(derived->Array);
}
template <typename T, typename S>
struct VTKM_ALWAYS_EXPORT Caster
{
vtkm::cont::ArrayHandle<T, S> operator()(const VariantArrayHandleContainerBase* container) const
{
//This needs to be reworked
using ArrayHandleType = vtkm::cont::ArrayHandle<T, S>;
if (!IsValueType<T>(container))
{
VTKM_LOG_CAST_FAIL(container, ArrayHandleType);
throwFailedDynamicCast(vtkm::cont::TypeToString(container),
vtkm::cont::TypeToString<ArrayHandleType>());
}
const auto* derived = static_cast<const VariantArrayHandleContainer<T>*>(container);
return vtkm::cont::Cast<vtkm::cont::ArrayHandle<T, S>>(derived->Array);
}
};
template <typename T>
struct VTKM_ALWAYS_EXPORT Caster<T, vtkm::cont::StorageTagVirtual>
{
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagVirtual> operator()(
const VariantArrayHandleContainerBase* container) const
{
if (!IsValueType<T>(container))
{
VTKM_LOG_CAST_FAIL(container, vtkm::cont::ArrayHandleVirtual<T>);
throwFailedDynamicCast(vtkm::cont::TypeToString(container),
vtkm::cont::TypeToString<vtkm::cont::ArrayHandleVirtual<T>>());
}
// Technically, this method returns a copy of the \c ArrayHandle. But
// because \c ArrayHandle acts like a shared pointer, it is valid to
// do the copy.
const auto* derived = static_cast<const VariantArrayHandleContainer<T>*>(container);
VTKM_LOG_CAST_SUCC(container, derived->Array);
return derived->Array;
}
};
// MSVC will issue deprecation warnings here if this template is instantiated with
// a deprecated class even if the template is used from a section of code where
// deprecation warnings are suppressed. This is annoying behavior since this template
// has no control over what class it is used with. To get around it, we have to
// suppress all deprecation warnings here.
#ifdef VTKM_MSVC
VTKM_DEPRECATED_SUPPRESS_BEGIN
#endif
template <typename ArrayHandleType>
VTKM_CONT ArrayHandleType Cast(const VariantArrayHandleContainerBase* container)
{ //container could be nullptr
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
using Type = typename ArrayHandleType::ValueType;
using Storage = typename ArrayHandleType::StorageTag;
auto ret = Caster<Type, Storage>{}(container);
return ArrayHandleType(std::move(ret));
}
#ifdef VTKM_MSVC
VTKM_DEPRECATED_SUPPRESS_END
#endif
struct ForceCastToVirtual
{
template <typename SrcValueType, typename Storage, typename DstValueType>
VTKM_CONT typename std::enable_if<std::is_same<SrcValueType, DstValueType>::value>::type
operator()(const vtkm::cont::ArrayHandle<SrcValueType, Storage>& input,
vtkm::cont::ArrayHandleVirtual<DstValueType>& output) const
{ // ValueTypes match
output = vtkm::cont::make_ArrayHandleVirtual<DstValueType>(input);
}
template <typename SrcValueType, typename Storage, typename DstValueType>
VTKM_CONT typename std::enable_if<!std::is_same<SrcValueType, DstValueType>::value>::type
operator()(const vtkm::cont::ArrayHandle<SrcValueType, Storage>& input,
vtkm::cont::ArrayHandleVirtual<DstValueType>& output) const
{ // ValueTypes do not match
this->ValidateWidthAndCast<SrcValueType, DstValueType>(input, output);
}
private:
template <typename S,
typename D,
typename InputType,
vtkm::IdComponent SSize = vtkm::VecTraits<S>::NUM_COMPONENTS,
vtkm::IdComponent DSize = vtkm::VecTraits<D>::NUM_COMPONENTS>
VTKM_CONT typename std::enable_if<SSize == DSize>::type ValidateWidthAndCast(
const InputType& input,
vtkm::cont::ArrayHandleVirtual<D>& output) const
{ // number of components match
auto casted = vtkm::cont::make_ArrayHandleCast<D>(input);
output = vtkm::cont::make_ArrayHandleVirtual<D>(casted);
}
template <typename S,
typename D,
vtkm::IdComponent SSize = vtkm::VecTraits<S>::NUM_COMPONENTS,
vtkm::IdComponent DSize = vtkm::VecTraits<D>::NUM_COMPONENTS>
VTKM_CONT typename std::enable_if<SSize != DSize>::type ValidateWidthAndCast(
const ArrayHandleBase&,
ArrayHandleBase&) const
{ // number of components do not match
std::ostringstream str;
str << "VariantArrayHandle::AsVirtual: Cannot cast from " << vtkm::cont::TypeToString<S>()
<< " to " << vtkm::cont::TypeToString<D>()
<< "; "
"number of components must match exactly.";
throw vtkm::cont::ErrorBadType(str.str());
}
};
} // namespace variant
} // namespace internal
namespace detail
{
VTKM_CONT_EXPORT void ThrowCastAndCallException(
const vtkm::cont::internal::VariantArrayHandleContainerBase&,
const std::type_info&);
VTKM_CONT_EXPORT void ThrowAsMultiplexerException(
const vtkm::cont::internal::VariantArrayHandleContainerBase& ref,
const std::initializer_list<std::string>& arrayTypes);
} // namespace detail
}
} //namespace vtkm::cont
#endif

@ -11,6 +11,7 @@
#include <vtkm/cont/ArrayHandle.h> #include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCounting.h> #include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleVirtual.h> #include <vtkm/cont/ArrayHandleVirtual.h>
#include <vtkm/cont/ArrayHandleVirtual.hxx>
#include <vtkm/cont/DeviceAdapterAlgorithm.h> #include <vtkm/cont/DeviceAdapterAlgorithm.h>

@ -157,27 +157,86 @@ vtkm::cont::UnknownArrayHandle CreateArrayUnknown(T t)
} }
template <typename ArrayHandleType> template <typename ArrayHandleType>
void CheckCastToArrayHandle(const ArrayHandleType& array) void CheckAsArrayHandle(const ArrayHandleType& array)
{ {
VTKM_IS_ARRAY_HANDLE(ArrayHandleType); VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
using T = typename ArrayHandleType::ValueType;
vtkm::cont::UnknownArrayHandle arrayUnknown = array; vtkm::cont::UnknownArrayHandle arrayUnknown = array;
VTKM_TEST_ASSERT(!arrayUnknown.IsType<vtkm::cont::ArrayHandle<UnusualType>>(), VTKM_TEST_ASSERT(!arrayUnknown.IsType<vtkm::cont::ArrayHandle<UnusualType>>(),
"Dynamic array reporting is wrong type."); "Dynamic array reporting is wrong type.");
ArrayHandleType castArray1; {
arrayUnknown.AsArrayHandle(castArray1); std::cout << " Normal get ArrayHandle" << std::endl;
VTKM_TEST_ASSERT(arrayUnknown.CanConvert<ArrayHandleType>(), "Did not query handle correctly."); ArrayHandleType retreivedArray1;
VTKM_TEST_ASSERT(array == castArray1, "Did not get back same array."); arrayUnknown.AsArrayHandle(retreivedArray1);
VTKM_TEST_ASSERT(arrayUnknown.CanConvert<ArrayHandleType>(), "Did not query handle correctly.");
VTKM_TEST_ASSERT(array == retreivedArray1, "Did not get back same array.");
ArrayHandleType castArray2 = arrayUnknown.AsArrayHandle<ArrayHandleType>(); ArrayHandleType retreivedArray2 = arrayUnknown.AsArrayHandle<ArrayHandleType>();
VTKM_TEST_ASSERT(array == castArray2, "Did not get back same array."); VTKM_TEST_ASSERT(array == retreivedArray2, "Did not get back same array.");
}
vtkm::cont::UnknownArrayHandle arrayUnknown2 = vtkm::cont::ArrayHandleMultiplexer< {
ArrayHandleType, std::cout << " Put in cast array, get actual array" << std::endl;
vtkm::cont::ArrayHandleConstant<typename ArrayHandleType::ValueType>>(array); auto castArray = vtkm::cont::make_ArrayHandleCast<vtkm::Float64>(array);
VTKM_TEST_ASSERT(arrayUnknown2.IsType<ArrayHandleType>(), vtkm::cont::UnknownArrayHandle arrayUnknown2(castArray);
"Putting in multiplexer did not pull out array."); VTKM_TEST_ASSERT(arrayUnknown2.IsType<ArrayHandleType>());
ArrayHandleType retrievedArray = arrayUnknown2.AsArrayHandle<ArrayHandleType>();
VTKM_TEST_ASSERT(array == retrievedArray);
}
{
std::cout << " Get array as cast" << std::endl;
vtkm::cont::ArrayHandleCast<vtkm::Float64, ArrayHandleType> castArray;
arrayUnknown.AsArrayHandle(castArray);
VTKM_TEST_ASSERT(test_equal_portals(array.ReadPortal(), castArray.ReadPortal()));
}
{
std::cout << " Put in multiplexer, get actual array" << std::endl;
vtkm::cont::UnknownArrayHandle arrayUnknown2 = vtkm::cont::ArrayHandleMultiplexer<
ArrayHandleType,
vtkm::cont::ArrayHandleConstant<typename ArrayHandleType::ValueType>>(array);
VTKM_TEST_ASSERT(arrayUnknown2.IsType<ArrayHandleType>(),
"Putting in multiplexer did not pull out array.");
}
{
std::cout << " Make sure multiplex array prefers direct array (1st arg)" << std::endl;
using MultiplexerType =
vtkm::cont::ArrayHandleMultiplexer<ArrayHandleType,
vtkm::cont::ArrayHandleCast<T, ArrayHandleType>>;
MultiplexerType multiplexArray = arrayUnknown.AsArrayHandle<MultiplexerType>();
VTKM_TEST_ASSERT(multiplexArray.IsValid());
VTKM_TEST_ASSERT(multiplexArray.GetStorage().GetArrayHandleVariant().GetIndex() == 0);
VTKM_TEST_ASSERT(test_equal_portals(multiplexArray.ReadPortal(), array.ReadPortal()));
}
{
std::cout << " Make sure multiplex array prefers direct array (2nd arg)" << std::endl;
using MultiplexerType =
vtkm::cont::ArrayHandleMultiplexer<vtkm::cont::ArrayHandleCast<T, vtkm::cont::ArrayHandle<T>>,
ArrayHandleType>;
MultiplexerType multiplexArray = arrayUnknown.AsArrayHandle<MultiplexerType>();
VTKM_TEST_ASSERT(multiplexArray.IsValid());
VTKM_TEST_ASSERT(multiplexArray.GetStorage().GetArrayHandleVariant().GetIndex() == 1);
VTKM_TEST_ASSERT(test_equal_portals(multiplexArray.ReadPortal(), array.ReadPortal()));
}
{
std::cout << " Make sure adding arrays follows nesting of special arrays" << std::endl;
vtkm::cont::ArrayHandleMultiplexer<vtkm::cont::ArrayHandle<vtkm::Int64>,
vtkm::cont::ArrayHandleCast<vtkm::Int64, ArrayHandleType>>
multiplexer(vtkm::cont::make_ArrayHandleCast<vtkm::Int64>(array));
auto crazyArray = vtkm::cont::make_ArrayHandleCast<vtkm::Float64>(multiplexer);
vtkm::cont::UnknownArrayHandle arrayUnknown2(crazyArray);
VTKM_TEST_ASSERT(arrayUnknown2.IsType<ArrayHandleType>());
ArrayHandleType retrievedArray = arrayUnknown2.AsArrayHandle<ArrayHandleType>();
VTKM_TEST_ASSERT(array == retrievedArray);
}
} }
// A vtkm::Vec if NumComps > 1, otherwise a scalar // A vtkm::Vec if NumComps > 1, otherwise a scalar
@ -320,12 +379,12 @@ void TryUnusualType()
} }
template <typename ArrayHandleType> template <typename ArrayHandleType>
void TryCastToArrayHandle(const ArrayHandleType& array) void TryAsArrayHandle(const ArrayHandleType& array)
{ {
CheckCastToArrayHandle(array); CheckAsArrayHandle(array);
} }
void TryCastToArrayHandle() void TryAsArrayHandle()
{ {
std::cout << " Normal array handle." << std::endl; std::cout << " Normal array handle." << std::endl;
vtkm::Id buffer[ARRAY_SIZE]; vtkm::Id buffer[ARRAY_SIZE];
@ -336,10 +395,10 @@ void TryCastToArrayHandle()
vtkm::cont::ArrayHandle<vtkm::Id> array = vtkm::cont::ArrayHandle<vtkm::Id> array =
vtkm::cont::make_ArrayHandle(buffer, ARRAY_SIZE, vtkm::CopyFlag::On); vtkm::cont::make_ArrayHandle(buffer, ARRAY_SIZE, vtkm::CopyFlag::On);
TryCastToArrayHandle(array); TryAsArrayHandle(array);
std::cout << " Constant array handle." << std::endl; std::cout << " Constant array handle." << std::endl;
TryCastToArrayHandle(vtkm::cont::make_ArrayHandleConstant(5, ARRAY_SIZE)); TryAsArrayHandle(vtkm::cont::make_ArrayHandleConstant(5, ARRAY_SIZE));
} }
void TrySetCastArray() void TrySetCastArray()
@ -386,8 +445,8 @@ void TestUnknownArrayHandle()
std::cout << "Try unusual type." << std::endl; std::cout << "Try unusual type." << std::endl;
TryUnusualType(); TryUnusualType();
std::cout << "Try CastToArrayHandle" << std::endl; std::cout << "Try AsArrayHandle" << std::endl;
TryCastToArrayHandle(); TryAsArrayHandle();
std::cout << "Try setting ArrayHandleCast" << std::endl; std::cout << "Try setting ArrayHandleCast" << std::endl;
TrySetCastArray(); TrySetCastArray();

@ -230,11 +230,16 @@ void CheckCastToArrayHandle(const ArrayHandleType& array)
ArrayHandleType castArray1; ArrayHandleType castArray1;
arrayVariant.CopyTo(castArray1); arrayVariant.CopyTo(castArray1);
VTKM_TEST_ASSERT(arrayVariant.IsType<ArrayHandleType>(), "Did not query handle correctly."); VTKM_TEST_ASSERT(arrayVariant.CanConvert<ArrayHandleType>(), "Did not query handle correctly.");
VTKM_TEST_ASSERT(array == castArray1, "Did not get back same array."); //VTKM_TEST_ASSERT(array == castArray1, "Did not get back same array.");
auto result = vtkm::cont::testing::test_equal_ArrayHandles(array, castArray1);
VTKM_TEST_ASSERT(result, result.GetMergedMessage());
ArrayHandleType castArray2 = arrayVariant.Cast<ArrayHandleType>(); ArrayHandleType castArray2 = arrayVariant.Cast<ArrayHandleType>();
VTKM_TEST_ASSERT(array == castArray2, "Did not get back same array."); //VTKM_TEST_ASSERT(array == castArray2, "Did not get back same array.");
result = vtkm::cont::testing::test_equal_ArrayHandles(array, castArray2);
VTKM_TEST_ASSERT(result, result.GetMergedMessage());
} }
// A vtkm::Vec if NumComps > 1, otherwise a scalar // A vtkm::Vec if NumComps > 1, otherwise a scalar