Merge topic 'convert-runtime-vec-array'

331a277fe Automatically convert between ArrayHandleBasic and ArrayHandleRuntimeVec

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Li-Ta Lo <ollie@lanl.gov>
Merge-request: !2994
This commit is contained in:
Kenneth Moreland 2023-03-08 19:35:20 +00:00 committed by Kitware Robot
commit 69a9d4a87e
9 changed files with 440 additions and 34 deletions

@ -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