mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-08 11:29:02 +00:00
Automatically convert between ArrayHandleBasic and ArrayHandleRuntimeVec
The `UnknownArrayHandle` has been updated to allow `ArrayHandleRuntimeVec` to work interchangeably with basic `ArrayHandle`. If an `ArrayHandleRuntimeVec` is put into an `UnknownArrayHandle`, it can be later retrieved as an `ArrayHandleBasic` as long as the base component type matches and it has the correct amount of components. This means that an array can be created as an `ArrayHandleRuntimeVec` and be used with any filters or most other features designed to operate on basic `ArrayHandle`s. Likewise, an array added as a basic `ArrayHandle` can be retrieved in an `ArrayHandleRuntimeVec`. This makes it easier to pull arrays from VTK-m and place them in external structures (such as `vtkDataArray`).
This commit is contained in:
parent
cf3c9bc921
commit
331a277fe3
@ -10,3 +10,14 @@ proper `Vec` value type. This allows one part of code (such as a file
|
||||
reader) to create an array with any `Vec` size, and then that array can be
|
||||
fed to an algorithm that expects an `ArrayHandleBasic` of a certain value
|
||||
type.
|
||||
|
||||
The `UnknownArrayHandle` has also been updated to allow
|
||||
`ArrayHandleRuntimeVec` to work interchangeably with basic `ArrayHandle`.
|
||||
If an `ArrayHandleRuntimeVec` is put into an `UnknownArrayHandle`, it can
|
||||
be later retrieved as an `ArrayHandleBasic` as long as the base component
|
||||
type matches and it has the correct amount of components. This means that
|
||||
an array can be created as an `ArrayHandleRuntimeVec` and be used with any
|
||||
filters or most other features designed to operate on basic `ArrayHandle`s.
|
||||
Likewise, an array added as a basic `ArrayHandle` can be retrieved in an
|
||||
`ArrayHandleRuntimeVec`. This makes it easier to pull arrays from VTK-m and
|
||||
place them in external structures (such as `vtkDataArray`).
|
||||
|
@ -136,6 +136,15 @@ struct VecTraits<vtkm::VecFromPortal<PortalType>>
|
||||
return vector[componentIndex];
|
||||
}
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
VTKM_EXEC_CONT
|
||||
static void SetComponent(const VecType& vector,
|
||||
vtkm::IdComponent componentIndex,
|
||||
const ComponentType& value)
|
||||
{
|
||||
vector[componentIndex] = value;
|
||||
}
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
template <vtkm::IdComponent destSize>
|
||||
VTKM_EXEC_CONT static void CopyInto(const VecType& src, vtkm::Vec<ComponentType, destSize>& dest)
|
||||
|
@ -26,6 +26,31 @@ namespace vtkm
|
||||
namespace internal
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
struct UnrollVecImpl
|
||||
{
|
||||
using type = vtkm::Vec<T, 1>;
|
||||
};
|
||||
|
||||
template <typename T, vtkm::IdComponent N>
|
||||
struct UnrollVecImpl<vtkm::Vec<T, N>>
|
||||
{
|
||||
using subtype = typename UnrollVecImpl<T>::type;
|
||||
using type = vtkm::Vec<typename subtype::ComponentType, subtype::NUM_COMPONENTS * N>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// A helper class that unrolls a nested `Vec` to a single layer `Vec`. This is similar
|
||||
// to `vtkm::VecFlat`, except that this only flattens `vtkm::Vec<T,N>` objects, and not
|
||||
// any other `Vec`-like objects. The reason is that a `vtkm::Vec<T,N>` is the same as N
|
||||
// consecutive `T` objects whereas the same may not be said about other `Vec`-like objects.
|
||||
template <typename T>
|
||||
using UnrollVec = typename detail::UnrollVecImpl<T>::type;
|
||||
|
||||
template <typename ComponentsPortalType>
|
||||
class VTKM_ALWAYS_EXPORT ArrayPortalRuntimeVec
|
||||
{
|
||||
@ -115,6 +140,12 @@ class Storage<vtkm::VecFromPortal<ComponentsPortal>, vtkm::cont::StorageTagRunti
|
||||
using ComponentsStorage =
|
||||
vtkm::cont::internal::Storage<ComponentType, vtkm::cont::StorageTagBasic>;
|
||||
|
||||
VTKM_STATIC_ASSERT_MSG(
|
||||
vtkm::internal::SafeVecTraits<ComponentType>::NUM_COMPONENTS == 1,
|
||||
"ArrayHandleRuntimeVec only supports scalars grouped into a single Vec. Nested Vecs can "
|
||||
"still be used with ArrayHandleRuntimeVec. The values are treated as flattened (like "
|
||||
"with VecFlat).");
|
||||
|
||||
using ComponentsArray = vtkm::cont::ArrayHandle<ComponentType, StorageTagBasic>;
|
||||
|
||||
VTKM_STATIC_ASSERT_MSG(
|
||||
@ -346,11 +377,28 @@ public:
|
||||
/// entries grouped in a Vec.
|
||||
///
|
||||
template <typename T>
|
||||
VTKM_CONT vtkm::cont::ArrayHandleRuntimeVec<T> make_ArrayHandleRuntimeVec(
|
||||
VTKM_CONT auto make_ArrayHandleRuntimeVec(
|
||||
vtkm::IdComponent numComponents,
|
||||
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>& componentsArray =
|
||||
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>{})
|
||||
{
|
||||
using UnrolledVec = vtkm::internal::UnrollVec<T>;
|
||||
using ComponentType = typename UnrolledVec::ComponentType;
|
||||
|
||||
// Use some dangerous magic to convert the basic array to its base component and create
|
||||
// an ArrayHandleRuntimeVec from that.
|
||||
vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagBasic> flatComponents(
|
||||
componentsArray.GetBuffers());
|
||||
|
||||
return vtkm::cont::ArrayHandleRuntimeVec<ComponentType>(
|
||||
numComponents * UnrolledVec::NUM_COMPONENTS, flatComponents);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
VTKM_CONT auto make_ArrayHandleRuntimeVec(
|
||||
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>& componentsArray)
|
||||
{
|
||||
return vtkm::cont::ArrayHandleRuntimeVec<T>(numComponents, componentsArray);
|
||||
return make_ArrayHandleRuntimeVec(1, componentsArray);
|
||||
}
|
||||
|
||||
namespace internal
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||
#include <vtkm/cont/ArrayHandlePermutation.h>
|
||||
#include <vtkm/cont/ArrayHandleReverse.h>
|
||||
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
|
||||
#include <vtkm/cont/ArrayHandleSOA.h>
|
||||
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
|
||||
#include <vtkm/cont/ErrorBadType.h>
|
||||
@ -45,12 +46,16 @@ struct AllVecImpl<N, vtkm::List<Scalars...>>
|
||||
template <vtkm::IdComponent N>
|
||||
using AllVec = typename AllVecImpl<N, vtkm::TypeListBaseC>::type;
|
||||
|
||||
template <typename T>
|
||||
using IsBasicStorage = std::is_same<vtkm::cont::StorageTagBasic, T>;
|
||||
template <typename List>
|
||||
using RemoveBasicStorage = vtkm::ListRemoveIf<List, IsBasicStorage>;
|
||||
|
||||
using UnknownSerializationTypes =
|
||||
vtkm::ListAppend<vtkm::TypeListBaseC, AllVec<2>, AllVec<3>, AllVec<4>>;
|
||||
using UnknownSerializationStorage =
|
||||
vtkm::ListAppend<VTKM_DEFAULT_STORAGE_LIST,
|
||||
vtkm::List<vtkm::cont::StorageTagBasic,
|
||||
vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic,
|
||||
using UnknownSerializationSpecializedStorage =
|
||||
vtkm::ListAppend<RemoveBasicStorage<VTKM_DEFAULT_STORAGE_LIST>,
|
||||
vtkm::List<vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic,
|
||||
vtkm::cont::StorageTagBasic,
|
||||
vtkm::cont::StorageTagBasic>,
|
||||
vtkm::cont::StorageTagConstant,
|
||||
@ -432,30 +437,82 @@ std::string SerializableTypeString<vtkm::cont::UnknownArrayHandle>::Get()
|
||||
}
|
||||
} // namespace vtkm::cont
|
||||
|
||||
namespace mangled_diy_namespace
|
||||
namespace
|
||||
{
|
||||
|
||||
void Serialization<vtkm::cont::UnknownArrayHandle>::save(BinaryBuffer& bb,
|
||||
const vtkm::cont::UnknownArrayHandle& obj)
|
||||
enum struct SerializedArrayType : vtkm::UInt8
|
||||
{
|
||||
BasicArray = 0,
|
||||
SpecializedStorage
|
||||
};
|
||||
|
||||
struct SaveBasicArray
|
||||
{
|
||||
template <typename ComponentType>
|
||||
VTKM_CONT void operator()(ComponentType,
|
||||
mangled_diy_namespace::BinaryBuffer& bb,
|
||||
const vtkm::cont::UnknownArrayHandle& obj,
|
||||
bool& saved)
|
||||
{
|
||||
// Basic arrays and arrays with compatible layouts can be loaed/saved as an
|
||||
// ArrayHandleRuntimeVec. Thus, we can load/save them all with one routine.
|
||||
using ArrayType = vtkm::cont::ArrayHandleRuntimeVec<ComponentType>;
|
||||
if (!saved && obj.CanConvert<ArrayType>())
|
||||
{
|
||||
ArrayType array = obj.AsArrayHandle<ArrayType>();
|
||||
vtkmdiy::save(bb, SerializedArrayType::BasicArray);
|
||||
vtkmdiy::save(bb, vtkm::cont::TypeToString<ComponentType>());
|
||||
vtkmdiy::save(bb, array);
|
||||
saved = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct LoadBasicArray
|
||||
{
|
||||
template <typename ComponentType>
|
||||
VTKM_CONT void operator()(ComponentType,
|
||||
mangled_diy_namespace::BinaryBuffer& bb,
|
||||
vtkm::cont::UnknownArrayHandle& obj,
|
||||
const std::string& componentTypeString,
|
||||
bool& loaded)
|
||||
{
|
||||
if (!loaded && (componentTypeString == vtkm::cont::TypeToString<ComponentType>()))
|
||||
{
|
||||
vtkm::cont::ArrayHandleRuntimeVec<ComponentType> array;
|
||||
vtkmdiy::load(bb, array);
|
||||
obj = array;
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
VTKM_CONT void SaveSpecializedArray(mangled_diy_namespace::BinaryBuffer& bb,
|
||||
const vtkm::cont::UnknownArrayHandle& obj)
|
||||
{
|
||||
vtkm::IdComponent numComponents = obj.GetNumberOfComponents();
|
||||
switch (numComponents)
|
||||
{
|
||||
case 1:
|
||||
vtkmdiy::save(bb, SerializedArrayType::SpecializedStorage);
|
||||
vtkmdiy::save(bb, numComponents);
|
||||
vtkmdiy::save(bb, obj.ResetTypes<vtkm::TypeListBaseC, UnknownSerializationStorage>());
|
||||
vtkmdiy::save(bb,
|
||||
obj.ResetTypes<vtkm::TypeListBaseC, UnknownSerializationSpecializedStorage>());
|
||||
break;
|
||||
case 2:
|
||||
vtkmdiy::save(bb, SerializedArrayType::SpecializedStorage);
|
||||
vtkmdiy::save(bb, numComponents);
|
||||
vtkmdiy::save(bb, obj.ResetTypes<AllVec<2>, UnknownSerializationStorage>());
|
||||
vtkmdiy::save(bb, obj.ResetTypes<AllVec<2>, UnknownSerializationSpecializedStorage>());
|
||||
break;
|
||||
case 3:
|
||||
vtkmdiy::save(bb, SerializedArrayType::SpecializedStorage);
|
||||
vtkmdiy::save(bb, numComponents);
|
||||
vtkmdiy::save(bb, obj.ResetTypes<AllVec<3>, UnknownSerializationStorage>());
|
||||
vtkmdiy::save(bb, obj.ResetTypes<AllVec<3>, UnknownSerializationSpecializedStorage>());
|
||||
break;
|
||||
case 4:
|
||||
vtkmdiy::save(bb, SerializedArrayType::SpecializedStorage);
|
||||
vtkmdiy::save(bb, numComponents);
|
||||
vtkmdiy::save(bb, obj.ResetTypes<AllVec<4>, UnknownSerializationStorage>());
|
||||
vtkmdiy::save(bb, obj.ResetTypes<AllVec<4>, UnknownSerializationSpecializedStorage>());
|
||||
break;
|
||||
default:
|
||||
throw vtkm::cont::ErrorBadType(
|
||||
@ -465,16 +522,17 @@ void Serialization<vtkm::cont::UnknownArrayHandle>::save(BinaryBuffer& bb,
|
||||
}
|
||||
}
|
||||
|
||||
void Serialization<vtkm::cont::UnknownArrayHandle>::load(BinaryBuffer& bb,
|
||||
vtkm::cont::UnknownArrayHandle& obj)
|
||||
VTKM_CONT void LoadSpecializedArray(mangled_diy_namespace::BinaryBuffer& bb,
|
||||
vtkm::cont::UnknownArrayHandle& obj)
|
||||
{
|
||||
vtkm::IdComponent numComponents;
|
||||
vtkmdiy::load(bb, numComponents);
|
||||
|
||||
vtkm::cont::UncertainArrayHandle<vtkm::TypeListBaseC, UnknownSerializationStorage> array1;
|
||||
vtkm::cont::UncertainArrayHandle<AllVec<2>, UnknownSerializationStorage> array2;
|
||||
vtkm::cont::UncertainArrayHandle<AllVec<3>, UnknownSerializationStorage> array3;
|
||||
vtkm::cont::UncertainArrayHandle<AllVec<4>, UnknownSerializationStorage> array4;
|
||||
vtkm::cont::UncertainArrayHandle<vtkm::TypeListBaseC, UnknownSerializationSpecializedStorage>
|
||||
array1;
|
||||
vtkm::cont::UncertainArrayHandle<AllVec<2>, UnknownSerializationSpecializedStorage> array2;
|
||||
vtkm::cont::UncertainArrayHandle<AllVec<3>, UnknownSerializationSpecializedStorage> array3;
|
||||
vtkm::cont::UncertainArrayHandle<AllVec<4>, UnknownSerializationSpecializedStorage> array4;
|
||||
|
||||
switch (numComponents)
|
||||
{
|
||||
@ -499,4 +557,53 @@ void Serialization<vtkm::cont::UnknownArrayHandle>::load(BinaryBuffer& bb,
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mangled_diy_namespace
|
||||
{
|
||||
|
||||
void Serialization<vtkm::cont::UnknownArrayHandle>::save(BinaryBuffer& bb,
|
||||
const vtkm::cont::UnknownArrayHandle& obj)
|
||||
{
|
||||
bool saved = false;
|
||||
|
||||
// First, try serializing basic arrays (which we can do for any Vec size).
|
||||
vtkm::ListForEach(SaveBasicArray{}, vtkm::TypeListBaseC{}, bb, obj, saved);
|
||||
|
||||
// If that did not work, try one of the specialized arrays.
|
||||
if (!saved)
|
||||
{
|
||||
SaveSpecializedArray(bb, obj);
|
||||
}
|
||||
}
|
||||
|
||||
void Serialization<vtkm::cont::UnknownArrayHandle>::load(BinaryBuffer& bb,
|
||||
vtkm::cont::UnknownArrayHandle& obj)
|
||||
{
|
||||
SerializedArrayType arrayType;
|
||||
vtkmdiy::load(bb, arrayType);
|
||||
|
||||
switch (arrayType)
|
||||
{
|
||||
case SerializedArrayType::BasicArray:
|
||||
{
|
||||
std::string componentTypeString;
|
||||
vtkmdiy::load(bb, componentTypeString);
|
||||
bool loaded = false;
|
||||
vtkm::ListForEach(
|
||||
LoadBasicArray{}, vtkm::TypeListBaseC{}, bb, obj, componentTypeString, loaded);
|
||||
if (!loaded)
|
||||
{
|
||||
throw vtkm::cont::ErrorInternal("Failed to load basic array. Unexpected buffer values.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SerializedArrayType::SpecializedStorage:
|
||||
LoadSpecializedArray(bb, obj);
|
||||
break;
|
||||
default:
|
||||
throw vtkm::cont::ErrorInternal("Got inappropriate enumeration value for loading array.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mangled_diy_namespace
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <vtkm/cont/ArrayHandleCast.h>
|
||||
#include <vtkm/cont/ArrayHandleMultiplexer.h>
|
||||
#include <vtkm/cont/ArrayHandleRecombineVec.h>
|
||||
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
|
||||
#include <vtkm/cont/ArrayHandleStride.h>
|
||||
#include <vtkm/cont/StorageList.h>
|
||||
|
||||
@ -42,6 +43,14 @@ void UnknownAHDelete(void* mem)
|
||||
delete arrayHandle;
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
const std::vector<vtkm::cont::internal::Buffer>& UnknownAHBuffers(void* mem)
|
||||
{
|
||||
using AH = vtkm::cont::ArrayHandle<T, S>;
|
||||
AH* arrayHandle = reinterpret_cast<AH*>(mem);
|
||||
return arrayHandle->GetBuffers();
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
void* UnknownAHNewInstance()
|
||||
{
|
||||
@ -259,6 +268,9 @@ struct VTKM_CONT_EXPORT UnknownAHContainer
|
||||
using DeleteType = void(void*);
|
||||
DeleteType* DeleteFunction;
|
||||
|
||||
using BuffersType = const std::vector<vtkm::cont::internal::Buffer>&(void*);
|
||||
BuffersType* Buffers;
|
||||
|
||||
using NewInstanceType = void*();
|
||||
NewInstanceType* NewInstance;
|
||||
|
||||
@ -383,6 +395,7 @@ inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle<T, S
|
||||
, BaseComponentType(
|
||||
UnknownAHComponentInfo::Make<typename vtkm::internal::SafeVecTraits<T>::BaseComponentType>())
|
||||
, DeleteFunction(detail::UnknownAHDelete<T, S>)
|
||||
, Buffers(detail::UnknownAHBuffers<T, S>)
|
||||
, NewInstance(detail::UnknownAHNewInstance<T, S>)
|
||||
, NewInstanceBasic(detail::UnknownAHNewInstanceBasic<T>)
|
||||
, NewInstanceFloatBasic(detail::UnknownAHNewInstanceFloatBasic<T>)
|
||||
@ -646,13 +659,10 @@ public:
|
||||
#ifdef VTKM_MSVC
|
||||
VTKM_DEPRECATED_SUPPRESS_BEGIN
|
||||
#endif
|
||||
///@{
|
||||
/// 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.
|
||||
/// Use the `CanConvert` method to determine if the array can be returned with the given type.
|
||||
///
|
||||
|
||||
private:
|
||||
template <typename T, typename S>
|
||||
VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle<T, S>& array) const
|
||||
VTKM_CONT void BaseAsArrayHandle(vtkm::cont::ArrayHandle<T, S>& array) const
|
||||
{
|
||||
using ArrayType = vtkm::cont::ArrayHandle<T, S>;
|
||||
if (!this->IsType<ArrayType>())
|
||||
@ -664,6 +674,21 @@ public:
|
||||
array = *reinterpret_cast<ArrayType*>(this->Container->ArrayHandlePointer);
|
||||
}
|
||||
|
||||
public:
|
||||
///@{
|
||||
/// 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.
|
||||
/// Use the `CanConvert` method to determine if the array can be returned with the given type.
|
||||
///
|
||||
template <typename T, typename S>
|
||||
VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle<T, S>& array) const
|
||||
{
|
||||
this->BaseAsArrayHandle(array);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle<T>& array) const;
|
||||
|
||||
template <typename T, typename... Ss>
|
||||
VTKM_CONT void AsArrayHandle(
|
||||
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagMultiplexer<Ss...>>& array) const;
|
||||
@ -677,6 +702,26 @@ public:
|
||||
this->AsArrayHandle<ContainedArrayType>());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
VTKM_CONT void AsArrayHandle(
|
||||
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagRuntimeVec>& array) const
|
||||
{
|
||||
using BaseT = typename T::ComponentType;
|
||||
if (this->IsStorageType<vtkm::cont::StorageTagBasic>() && this->IsBaseComponentType<BaseT>())
|
||||
{
|
||||
// Reinterpret the basic array as components, and then wrap that in a runtime vec
|
||||
// with the correct amount of components.
|
||||
vtkm::cont::ArrayHandle<BaseT, vtkm::cont::StorageTagBasic> basicArray(
|
||||
this->Container->Buffers(this->Container->ArrayHandlePointer));
|
||||
array =
|
||||
vtkm::cont::ArrayHandleRuntimeVec<BaseT>(this->GetNumberOfComponentsFlat(), basicArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->BaseAsArrayHandle(array);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ArrayType>
|
||||
VTKM_CONT ArrayType AsArrayHandle() const
|
||||
{
|
||||
@ -916,6 +961,19 @@ struct UnknownArrayHandleCanConvert
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnknownArrayHandleCanConvert<T, vtkm::cont::StorageTagBasic>
|
||||
{
|
||||
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const
|
||||
{
|
||||
using UnrolledVec = vtkm::internal::UnrollVec<T>;
|
||||
return (array.IsType<vtkm::cont::ArrayHandleBasic<T>>() ||
|
||||
(array.IsStorageType<vtkm::cont::StorageTagRuntimeVec>() &&
|
||||
array.IsBaseComponentType<typename UnrolledVec::ComponentType>() &&
|
||||
UnrolledVec::NUM_COMPONENTS == array.GetNumberOfComponentsFlat()));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TargetT, typename SourceT, typename SourceS>
|
||||
struct UnknownArrayHandleCanConvert<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceS>>
|
||||
{
|
||||
@ -946,10 +1004,22 @@ struct UnknownArrayHandleCanConvert<T, vtkm::cont::StorageTagMultiplexer<Ss...>>
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnknownArrayHandleCanConvert<T, vtkm::cont::StorageTagRuntimeVec>
|
||||
{
|
||||
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const
|
||||
{
|
||||
using BaseComponentType = typename T::ComponentType;
|
||||
return (array.IsType<vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagRuntimeVec>>() ||
|
||||
(array.IsStorageType<vtkm::cont::StorageTagBasic>() &&
|
||||
array.IsBaseComponentType<BaseComponentType>()));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename ArrayHandleType>
|
||||
VTKM_CONT bool UnknownArrayHandle::CanConvert() const
|
||||
VTKM_CONT inline bool UnknownArrayHandle::CanConvert() const
|
||||
{
|
||||
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
|
||||
|
||||
@ -960,6 +1030,66 @@ VTKM_CONT bool UnknownArrayHandle::CanConvert() const
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename T,
|
||||
vtkm::IdComponent = vtkm::internal::SafeVecTraits<
|
||||
typename vtkm::internal::UnrollVec<T>::ComponentType>::NUM_COMPONENTS>
|
||||
struct UnknownArrayHandleRuntimeVecAsBasic
|
||||
{
|
||||
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle*,
|
||||
const detail::UnknownAHContainer*,
|
||||
vtkm::cont::ArrayHandle<T>&) const
|
||||
{
|
||||
// This version only gets called if T contains a `Vec`-like object that is not a strict `Vec`.
|
||||
// This is rare but could happen. In this case, the type cannot be stored in an
|
||||
// `ArrayHandleRuntimeVec` and therefore the load can never happen, so just ignore.
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnknownArrayHandleRuntimeVecAsBasic<T, 1>
|
||||
{
|
||||
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle* self,
|
||||
const detail::UnknownAHContainer* container,
|
||||
vtkm::cont::ArrayHandle<T>& array) const
|
||||
{
|
||||
using UnrolledVec = vtkm::internal::UnrollVec<T>;
|
||||
using ComponentType = typename UnrolledVec::ComponentType;
|
||||
if (self->IsStorageType<vtkm::cont::StorageTagRuntimeVec>() &&
|
||||
self->IsBaseComponentType<ComponentType>() &&
|
||||
UnrolledVec::NUM_COMPONENTS == self->GetNumberOfComponentsFlat())
|
||||
{
|
||||
// Pull out the components array out of the buffers. The array might not match exactly
|
||||
// the array put in, but the buffer should still be consistent with the array (which works
|
||||
// because the size of a basic array is based on the number of bytes in the buffer).
|
||||
using RuntimeVecType = typename vtkm::cont::ArrayHandleRuntimeVec<ComponentType>::ValueType;
|
||||
using StorageRuntimeVec =
|
||||
vtkm::cont::internal::Storage<RuntimeVecType, vtkm::cont::StorageTagRuntimeVec>;
|
||||
StorageRuntimeVec::AsArrayHandleBasic(container->Buffers(container->ArrayHandlePointer),
|
||||
array);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
VTKM_CONT inline void UnknownArrayHandle::AsArrayHandle(vtkm::cont::ArrayHandle<T>& array) const
|
||||
{
|
||||
if (!detail::UnknownArrayHandleRuntimeVecAsBasic<T>{}(this, this->Container.get(), array))
|
||||
{
|
||||
this->BaseAsArrayHandle(array);
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
struct UnknownArrayHandleMultiplexerCastTry
|
||||
{
|
||||
template <typename T, typename S, typename... Ss>
|
||||
|
@ -230,13 +230,13 @@ void DoTest()
|
||||
|
||||
{
|
||||
std::cout << "ArrayHandleRuntimeVec" << std::endl;
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f> array;
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> array;
|
||||
array.Allocate(ARRAY_SIZE * 4);
|
||||
SetPortal(array.WritePortal());
|
||||
CheckOutputArray(vtkm::cont::make_ArrayHandleRuntimeVec(2, array),
|
||||
vtkm::cont::ArrayHandleRuntimeVec<vtkm::Vec3f>(2));
|
||||
vtkm::cont::ArrayHandleRuntimeVec<vtkm::FloatDefault>(2));
|
||||
CheckOutputArray(vtkm::cont::make_ArrayHandleRuntimeVec(4, array),
|
||||
vtkm::cont::ArrayHandleRuntimeVec<vtkm::Vec3f>(4));
|
||||
vtkm::cont::ArrayHandleRuntimeVec<vtkm::FloatDefault>(4));
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
|
||||
|
||||
#include <vtkm/cont/ArrayHandleGroupVec.h>
|
||||
#include <vtkm/cont/Invoker.h>
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
@ -64,7 +65,52 @@ struct PassThrough : vtkm::worklet::WorkletMapField
|
||||
template <typename InValue, typename OutValue>
|
||||
VTKM_EXEC void operator()(const InValue& inValue, OutValue& outValue) const
|
||||
{
|
||||
outValue = inValue;
|
||||
vtkm::IdComponent inIndex = 0;
|
||||
vtkm::IdComponent outIndex = 0;
|
||||
this->FlatCopy(inValue, inIndex, outValue, outIndex);
|
||||
}
|
||||
|
||||
template <typename InValue, typename OutValue>
|
||||
VTKM_EXEC void FlatCopy(const InValue& inValue,
|
||||
vtkm::IdComponent& inIndex,
|
||||
OutValue& outValue,
|
||||
vtkm::IdComponent& outIndex) const
|
||||
{
|
||||
using VTraitsIn = vtkm::internal::SafeVecTraits<InValue>;
|
||||
using VTraitsOut = vtkm::internal::SafeVecTraits<OutValue>;
|
||||
VTraitsOut::SetComponent(outValue, outIndex, VTraitsIn::GetComponent(inValue, inIndex));
|
||||
inIndex++;
|
||||
outIndex++;
|
||||
}
|
||||
|
||||
template <typename InComponent, vtkm::IdComponent InN, typename OutValue>
|
||||
VTKM_EXEC void FlatCopy(const vtkm::Vec<InComponent, InN>& inValue,
|
||||
vtkm::IdComponent& inIndex,
|
||||
OutValue& outValue,
|
||||
vtkm::IdComponent& outIndex) const
|
||||
{
|
||||
VTKM_ASSERT(inIndex == 0);
|
||||
for (vtkm::IdComponent i = 0; i < InN; ++i)
|
||||
{
|
||||
FlatCopy(inValue[i], inIndex, outValue, outIndex);
|
||||
inIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InValue, typename OutComponent, vtkm::IdComponent OutN>
|
||||
VTKM_EXEC void FlatCopy(const InValue& inValue,
|
||||
vtkm::IdComponent& inIndex,
|
||||
vtkm::Vec<OutComponent, OutN>& outValue,
|
||||
vtkm::IdComponent& outIndex) const
|
||||
{
|
||||
VTKM_ASSERT(outIndex == 0);
|
||||
for (vtkm::IdComponent i = 0; i < OutN; ++i)
|
||||
{
|
||||
OutComponent outComponent;
|
||||
FlatCopy(inValue, inIndex, outComponent, outIndex);
|
||||
outValue[i] = outComponent;
|
||||
outIndex = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -80,7 +126,7 @@ struct TestRuntimeVecAsInput
|
||||
baseArray.Allocate(ARRAY_SIZE * NUM_COMPONENTS);
|
||||
SetPortal(baseArray.WritePortal());
|
||||
|
||||
vtkm::cont::ArrayHandleRuntimeVec<ComponentType> runtimeVecArray(NUM_COMPONENTS, baseArray);
|
||||
auto runtimeVecArray = vtkm::cont::make_ArrayHandleRuntimeVec(NUM_COMPONENTS, baseArray);
|
||||
VTKM_TEST_ASSERT(runtimeVecArray.GetNumberOfValues() == ARRAY_SIZE,
|
||||
"Group array reporting wrong array size.");
|
||||
|
||||
@ -108,7 +154,8 @@ struct TestRuntimeVecAsInput
|
||||
//verify that you can get the data as a basic array
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<ComponentType, NUM_COMPONENTS>> flatComponents;
|
||||
runtimeVecArray.AsArrayHandleBasic(flatComponents);
|
||||
VTKM_TEST_ASSERT(test_equal_ArrayHandles(flatComponents, runtimeVecArray));
|
||||
VTKM_TEST_ASSERT(test_equal_ArrayHandles(
|
||||
flatComponents, vtkm::cont::make_ArrayHandleGroupVec<NUM_COMPONENTS>(baseArray)));
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Vec<ComponentType, 1>, NUM_COMPONENTS>>
|
||||
nestedComponents;
|
||||
|
@ -313,8 +313,7 @@ struct TestArrayHandleRuntimeVec
|
||||
auto flat = RandomArrayHandle<T>::Make(ArraySize * numComps);
|
||||
auto array = vtkm::cont::make_ArrayHandleRuntimeVec(numComps, flat);
|
||||
RunTest(array);
|
||||
// TODO: Add this back once UnknownArrayHandle supports ArrayHandleRuntimeVec more fully.
|
||||
//RunTest(MakeTestUnknownArrayHandle(array));
|
||||
RunTest(MakeTestUnknownArrayHandle(array));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <vtkm/cont/ArrayHandleCounting.h>
|
||||
#include <vtkm/cont/ArrayHandleGroupVecVariable.h>
|
||||
#include <vtkm/cont/ArrayHandleMultiplexer.h>
|
||||
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
|
||||
|
||||
#include <vtkm/TypeTraits.h>
|
||||
|
||||
@ -542,6 +543,57 @@ void TrySetMultiplexerArray()
|
||||
CheckUnknownArray<vtkm::List<vtkm::Id>, vtkm::List<VTKM_DEFAULT_STORAGE_TAG>>(unknownArray, 1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void TryConvertRuntimeVec()
|
||||
{
|
||||
using BasicArrayType = vtkm::cont::ArrayHandle<T>;
|
||||
using BasicComponentType = typename vtkm::VecFlat<T>::ComponentType;
|
||||
constexpr vtkm::IdComponent numFlatComponents = vtkm::VecFlat<T>::NUM_COMPONENTS;
|
||||
using RuntimeArrayType = vtkm::cont::ArrayHandleRuntimeVec<BasicComponentType>;
|
||||
|
||||
std::cout << " Get basic array as ArrayHandleRuntimeVec" << std::endl;
|
||||
BasicArrayType inputArray;
|
||||
inputArray.Allocate(ARRAY_SIZE);
|
||||
SetPortal(inputArray.WritePortal());
|
||||
|
||||
vtkm::cont::UnknownArrayHandle unknownWithBasic{ inputArray };
|
||||
VTKM_TEST_ASSERT(unknownWithBasic.GetNumberOfComponentsFlat() == numFlatComponents);
|
||||
|
||||
VTKM_TEST_ASSERT(unknownWithBasic.CanConvert<RuntimeArrayType>());
|
||||
RuntimeArrayType runtimeArray = unknownWithBasic.AsArrayHandle<RuntimeArrayType>();
|
||||
|
||||
// Hack to convert the array handle to a flat array to make it easy to check the runtime array
|
||||
vtkm::cont::ArrayHandle<vtkm::VecFlat<T>> flatInput{ inputArray.GetBuffers() };
|
||||
VTKM_TEST_ASSERT(test_equal_ArrayHandles(flatInput, runtimeArray));
|
||||
|
||||
std::cout << " Get ArrayHandleRuntimeVec as basic array" << std::endl;
|
||||
vtkm::cont::UnknownArrayHandle unknownWithRuntimeVec{ runtimeArray };
|
||||
VTKM_TEST_ASSERT(unknownWithRuntimeVec.GetNumberOfComponentsFlat() == numFlatComponents);
|
||||
|
||||
VTKM_TEST_ASSERT(unknownWithRuntimeVec.CanConvert<RuntimeArrayType>());
|
||||
VTKM_TEST_ASSERT(unknownWithRuntimeVec.CanConvert<BasicArrayType>());
|
||||
BasicArrayType outputArray = unknownWithRuntimeVec.AsArrayHandle<BasicArrayType>();
|
||||
VTKM_TEST_ASSERT(test_equal_ArrayHandles(inputArray, outputArray));
|
||||
}
|
||||
|
||||
void TryConvertRuntimeVec()
|
||||
{
|
||||
std::cout << " Scalar array." << std::endl;
|
||||
TryConvertRuntimeVec<vtkm::FloatDefault>();
|
||||
|
||||
std::cout << " Equivalent scalar." << std::endl;
|
||||
TryConvertRuntimeVec<VTKM_UNUSED_INT_TYPE>();
|
||||
|
||||
std::cout << " Basic Vec." << std::endl;
|
||||
TryConvertRuntimeVec<vtkm::Id3>();
|
||||
|
||||
std::cout << " Vec of Vecs." << std::endl;
|
||||
TryConvertRuntimeVec<vtkm::Vec<vtkm::Vec2f, 3>>();
|
||||
|
||||
std::cout << " Vec of Vecs of Vecs." << std::endl;
|
||||
TryConvertRuntimeVec<vtkm::Vec<vtkm::Vec<vtkm::Id4, 3>, 2>>();
|
||||
}
|
||||
|
||||
struct DefaultTypeFunctor
|
||||
{
|
||||
template <typename T>
|
||||
@ -573,6 +625,9 @@ void TestUnknownArrayHandle()
|
||||
|
||||
std::cout << "Try setting ArrayHandleMultiplexer" << std::endl;
|
||||
TrySetMultiplexerArray();
|
||||
|
||||
std::cout << "Try converting between ArrayHandleRuntimeVec and basic array" << std::endl;
|
||||
TryConvertRuntimeVec();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
Loading…
Reference in New Issue
Block a user