Correct IsType and Cast on ArrayHandleVirtual to work on OSX.

This commit is contained in:
Robert Maynard 2018-12-18 15:10:55 -05:00
parent 7b9fa975f2
commit acf825b279
10 changed files with 117 additions and 64 deletions

@ -51,16 +51,6 @@ public:
void ReleaseResources();
private:
// StorageAny is meant to be seamless when it comes to IsType so we will match
// when either the type_info is 'StorageAny<T,S>' or 'Storage<T,S>'. That is why
// we need to override the default implementation.
bool IsSameType(const std::type_info& other) const
{
//We don't wan to check just 'S' as that just the tag
using ST = typename vtkm::cont::internal::Storage<T, S>;
return other == typeid(ST) || other == typeid(*this);
}
std::unique_ptr<StorageVirtual> MakeNewInstance() const
{
return std::unique_ptr<StorageVirtual>(new StorageAny<T, S>{ vtkm::cont::ArrayHandle<T, S>{} });

@ -115,7 +115,8 @@ private:
/// array at that position.
///
template <class FunctorType>
class ArrayHandleImplicit : public detail::ArrayHandleImplicitTraits<FunctorType>::Superclass
class VTKM_ALWAYS_EXPORT ArrayHandleImplicit
: public detail::ArrayHandleImplicitTraits<FunctorType>::Superclass
{
private:
using ArrayTraits = typename detail::ArrayHandleImplicitTraits<FunctorType>;

@ -134,7 +134,6 @@ public:
return true; // different valuetype and/or storage
}
/// Returns true if this array's storage matches the type passed in.
///
template <typename ArrayHandleType>
@ -155,6 +154,28 @@ public:
return this->IsSameType<ArrayHandleType>(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 <typename ArrayHandleType>
VTKM_CONT ArrayHandleType Cast() const
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
using VT = typename ArrayHandleType::ValueType;
static_assert(
std::is_same<VT, T>::value,
"ArrayHandleVirtual<ValueType> can only be casted to an ArrayHandle of the same ValueType.");
//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<vtkm::cont::StorageTagVirtual, ST>;
return this->CastToType<ArrayHandleType>(is_base{});
}
/// Returns a new instance of an ArrayHandleVirtual with the same storage
///
VTKM_CONT ArrayHandle<T, ::vtkm::cont::StorageTagVirtual> NewInstance() const
@ -285,19 +306,36 @@ private:
bool IsSameType(std::true_type vtkmNotUsed(inheritsFromArrayHandleVirtual)) const
{
//All classes that derive from ArrayHandleVirtual have virtual methods so we can use
//typeid directly
return typeid(*this) == typeid(ArrayHandleType);
//typeid directly.
//needs optimizations based on platform. !OSX can use typeid
return nullptr != dynamic_cast<const ArrayHandleType*>(this);
}
template <typename ArrayHandleType>
bool IsSameType(std::false_type vtkmNotUsed(notFromArrayHandleVirtual)) const
bool IsSameType(std::false_type vtkmNotUsed(notFromArrayHandleVirtual)) const;
template <typename ArrayHandleType>
ArrayHandleType CastToType(std::true_type vtkmNotUsed(inheritsFromArrayHandleVirtual)) const
{
//We need to go long the way to find the StorageType
//as StorageType is private on lots of derived ArrayHandles
//See Issue #314
using ST = typename ArrayHandleType::StorageTag;
return this->Storage->IsType(typeid(vtkm::cont::internal::Storage<T, ST>));
//All classes that derive from ArrayHandleVirtual have virtual methods so we can use
//dynamic_cast directly
if (!this->Storage)
{
VTKM_LOG_CAST_FAIL(*this, ArrayHandleType);
throwFailedDynamicCast("ArrayHandleVirtual", vtkm::cont::TypeName<ArrayHandleType>());
}
const ArrayHandleType* derived = dynamic_cast<const ArrayHandleType*>(this);
if (!derived)
{
VTKM_LOG_CAST_FAIL(*this, ArrayHandleType);
throwFailedDynamicCast("ArrayHandleVirtual", vtkm::cont::TypeName<ArrayHandleType>());
}
VTKM_LOG_CAST_SUCC(*this, derived);
return *derived;
}
template <typename ArrayHandleType>
ArrayHandleType CastToType(std::false_type vtkmNotUsed(notFromArrayHandleVirtual)) const;
};
//=============================================================================
@ -306,6 +344,23 @@ template <typename T>
using ArrayHandleVirtual = vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagVirtual>;
//=============================================================================
// Free function casting helpers
template <typename ArrayHandleType, typename T>
VTKM_CONT inline bool IsType(const vtkm::cont::ArrayHandleVirtual<T>& virtHandle)
{
return virtHandle.template IsType<ArrayHandleType>();
}
template <typename ArrayHandleType, typename T>
VTKM_CONT inline ArrayHandleType Cast(const vtkm::cont::ArrayHandleVirtual<T>& virtHandle)
{
return virtHandle.template Cast<ArrayHandleType>();
}
//=============================================================================
// Specializations of serialization related classes
template <typename T>

@ -22,12 +22,43 @@
#include <vtkm/cont/ArrayHandleVirtual.h>
#include <vtkm/cont/ArrayHandleAny.h>
#include <vtkm/cont/TryExecute.h>
namespace vtkm
{
namespace cont
{
template <typename T>
template <typename ArrayHandleType>
bool ArrayHandle<T, StorageTagVirtual>::IsSameType(
std::false_type vtkmNotUsed(notFromArrayHandleVirtual)) const
{
if (!this->Storage)
{
return false;
}
using S = typename ArrayHandleType::StorageTag;
return this->Storage->template IsType<vtkm::cont::StorageAny<T, S>>();
}
template <typename T>
template <typename ArrayHandleType>
ArrayHandleType ArrayHandle<T, StorageTagVirtual>::CastToType(
std::false_type vtkmNotUsed(notFromArrayHandleVirtual)) const
{
if (!this->Storage)
{
VTKM_LOG_CAST_FAIL(*this, ArrayHandleType);
throwFailedDynamicCast("ArrayHandleVirtual", vtkm::cont::TypeName<ArrayHandleType>());
}
using S = typename ArrayHandleType::StorageTag;
const auto* any = this->Storage->template Cast<vtkm::cont::StorageAny<T, S>>();
return any->GetHandle();
}
namespace detail
{
template <typename DerivedPortal>
@ -69,7 +100,6 @@ inline void make_hostPortal(Payload&& payload, Args&&... args)
#include <vtkm/cont/ArrayHandleAny.h>
//=============================================================================
// Specializations of serialization related classes
namespace diy

@ -40,7 +40,7 @@ namespace cont
{
/// ArrayHandleVirtualCoordinates is a specialization of ArrayHandle.
class VTKM_CONT_EXPORT ArrayHandleVirtualCoordinates final
class VTKM_ALWAYS_EXPORT ArrayHandleVirtualCoordinates final
: public vtkm::cont::ArrayHandleVirtual<vtkm::Vec<vtkm::FloatDefault, 3>>
{
public:
@ -77,20 +77,6 @@ public:
using ST = typename decltype(castedHandle)::StorageTag;
this->Storage = std::make_shared<vtkm::cont::StorageAny<ValueType, ST>>(castedHandle);
}
/// 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 <typename ArrayHandleType>
VTKM_CONT ArrayHandleType Cast() const
{
using T = typename ArrayHandleType::ValueType;
using S = typename ArrayHandleType::StorageTag;
const vtkm::cont::StorageVirtual* storage = this->GetStorage();
const auto* any = storage->Cast<vtkm::cont::StorageAny<T, S>>();
return any->GetHandle();
}
};
template <typename Functor, typename... Args>
@ -111,7 +97,6 @@ void CastAndCall(const vtkm::cont::ArrayHandleVirtualCoordinates& coords,
}
template <>
struct TypeString<vtkm::cont::ArrayHandleVirtualCoordinates>
{

@ -53,7 +53,8 @@ namespace internal
{
template <class ArrayPortalType>
class Storage<typename ArrayPortalType::ValueType, StorageTagImplicit<ArrayPortalType>>
class VTKM_ALWAYS_EXPORT
Storage<typename ArrayPortalType::ValueType, StorageTagImplicit<ArrayPortalType>>
{
using ClassType =
Storage<typename ArrayPortalType::ValueType, StorageTagImplicit<ArrayPortalType>>;

@ -87,12 +87,6 @@ void Storage<void, ::vtkm::cont::StorageTagVirtual>::ReleaseResources()
this->DeviceUpToDate = false;
}
//--------------------------------------------------------------------
bool Storage<void, ::vtkm::cont::StorageTagVirtual>::IsSameType(const std::type_info& other) const
{
return typeid(*this) == other;
}
//--------------------------------------------------------------------
std::unique_ptr<Storage<void, ::vtkm::cont::StorageTagVirtual>>
Storage<void, ::vtkm::cont::StorageTagVirtual>::NewInstance() const

@ -34,7 +34,7 @@ namespace vtkm
namespace cont
{
struct StorageTagVirtual
struct VTKM_ALWAYS_EXPORT StorageTagVirtual
{
};
@ -99,7 +99,11 @@ public:
/// Determines if storage types matches the type passed in.
///
bool IsType(const std::type_info& other) const { return this->IsSameType(other); }
template <typename DerivedStorage>
bool IsType() const
{ //needs optimizations based on platform. !OSX can use typeid
return nullptr != dynamic_cast<const DerivedStorage*>(this);
}
/// \brief Create a new storage of the same type as this storage.
///
@ -155,7 +159,6 @@ private:
// virtual void DoShrink(vtkm::Id numberOfValues) = 0;
//RTTI routines
virtual bool IsSameType(const std::type_info&) const;
virtual std::unique_ptr<Storage<void, ::vtkm::cont::StorageTagVirtual>> MakeNewInstance()
const = 0;

@ -89,31 +89,23 @@ struct Transport<vtkm::cont::arg::TransportTagAtomicArray,
vtkm::Id,
vtkm::Id) const
{
using S = vtkm::cont::StorageTagBasic;
const vtkm::cont::StorageVirtual* storage = array.GetStorage();
if (!storage)
{
throw vtkm::cont::ErrorBadValue("ArrayHandleVirtual must not have a nullptr for storage.");
}
if (!storage->IsType(typeid(vtkm::cont::internal::Storage<T, S>)))
using ArrayHandleType = vtkm::cont::ArrayHandle<T>;
const bool is_type = vtkm::cont::IsType<ArrayHandleType>(array);
if (!is_type)
{
#if defined(VTKM_ENABLE_LOGGING)
using AH = vtkm::cont::ArrayHandle<T, S>;
VTKM_LOG_CAST_FAIL(array, AH);
VTKM_LOG_CAST_FAIL(array, ArrayHandleType);
#endif
throw vtkm::cont::ErrorBadValue("Arrays being used as atomic's must always have storage that "
"is of the type StorageTagBasic.");
}
const auto* any = static_cast<const vtkm::cont::StorageAny<T, S>*>(storage);
VTKM_LOG_CAST_SUCC(array, *any);
ArrayHandleType handle = vtkm::cont::Cast<ArrayHandleType>(array);
// Note: we ignore the size of the domain because the randomly accessed
// array might not have the same size depending on how the user is using
// the array.
ExecType obj(any->GetHandle());
ExecType obj(handle);
return obj.PrepareForExecution(Device());
}
};

@ -137,11 +137,11 @@ VTKM_CONT bool IsType(const VariantArrayHandleContainerBase* container)
{
return false;
}
using VT = typename ArrayHandleType::ValueType;
using ST = typename ArrayHandleType::StorageTag;
const vtkm::cont::StorageVirtual* storage = container->GetStorage();
return storage->IsType(typeid(vtkm::cont::internal::Storage<VT, ST>));
return storage->IsType<vtkm::cont::StorageAny<VT, ST>>();
}
template <typename T>
@ -151,7 +151,9 @@ VTKM_CONT bool IsValueType(const VariantArrayHandleContainerBase* container)
{ //you can't use typeid on nullptr of polymorphic types
return false;
}
return typeid(VariantArrayHandleContainer<T>) == typeid(*container);
//needs optimizations based on platform. !OSX can use typeid
return (nullptr != dynamic_cast<const VariantArrayHandleContainer<T>*>(container));
}