Enable writing to ArrayHandleCast

Previously, `ArrayHandleCast` was considered a read-only array handle.
However, it is trivial to reverse the cast (now that `ArrayHandleTransform`
supports an inverse transform). So now you can write to a cast array
(assuming the underlying array is writable).

One trivial consequence of this change is that you can no longer make a
cast that cannot be reversed. For example, it was possible to cast a simple
scalar to a `Vec` even though it is not possible to convert a `Vec` to a
scalar value. This was of dubious correctness (it is more of a construction
than a cast) and is easy to recreate with `ArrayHandleTransform`.
This commit is contained in:
Kenneth Moreland 2019-07-17 18:40:45 -06:00
parent 6d37ce9453
commit 0e15a1116c
4 changed files with 67 additions and 4 deletions

@ -0,0 +1,12 @@
# Enable writing to ArrayHandleCast
Previously, `ArrayHandleCast` was considered a read-only array handle.
However, it is trivial to reverse the cast (now that `ArrayHandleTransform`
supports an inverse transform). So now you can write to a cast array
(assuming the underlying array is writable).
One trivial consequence of this change is that you can no longer make a
cast that cannot be reversed. For example, it was possible to cast a simple
scalar to a `Vec` even though it is not possible to convert a `Vec` to a
scalar value. This was of dubious correctness (it is more of a construction
than a cast) and is easy to recreate with `ArrayHandleTransform`.

@ -45,14 +45,16 @@ struct VTKM_ALWAYS_EXPORT Cast
template <typename T, typename ArrayHandleType>
class ArrayHandleCast
: public vtkm::cont::ArrayHandleTransform<ArrayHandleType,
internal::Cast<typename ArrayHandleType::ValueType, T>>
internal::Cast<typename ArrayHandleType::ValueType, T>,
internal::Cast<T, typename ArrayHandleType::ValueType>>
{
public:
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandleCast,
(ArrayHandleCast<T, ArrayHandleType>),
(vtkm::cont::ArrayHandleTransform<ArrayHandleType,
internal::Cast<typename ArrayHandleType::ValueType, T>>));
internal::Cast<typename ArrayHandleType::ValueType, T>,
internal::Cast<T, typename ArrayHandleType::ValueType>>));
ArrayHandleCast(const ArrayHandleType& handle)
: Superclass(handle)
@ -172,7 +174,9 @@ struct SerializableTypeString<vtkm::cont::internal::Cast<T1, T2>>
template <typename T, typename AH>
struct SerializableTypeString<vtkm::cont::ArrayHandleCast<T, AH>>
: SerializableTypeString<
vtkm::cont::ArrayHandleTransform<AH, vtkm::cont::internal::Cast<typename AH::ValueType, T>>>
vtkm::cont::ArrayHandleTransform<AH,
vtkm::cont::internal::Cast<typename AH::ValueType, T>,
vtkm::cont::internal::Cast<T, typename AH::ValueType>>>
{
};
}
@ -192,7 +196,9 @@ struct Serialization<vtkm::cont::internal::Cast<T1, T2>>
template <typename T, typename AH>
struct Serialization<vtkm::cont::ArrayHandleCast<T, AH>>
: Serialization<
vtkm::cont::ArrayHandleTransform<AH, vtkm::cont::internal::Cast<typename AH::ValueType, T>>>
vtkm::cont::ArrayHandleTransform<AH,
vtkm::cont::internal::Cast<typename AH::ValueType, T>,
vtkm::cont::internal::Cast<T, typename AH::ValueType>>>
{
};

@ -681,6 +681,37 @@ private:
}
};
struct TestCastAsOutput
{
template <typename CastFromType>
VTKM_CONT void operator()(CastFromType vtkmNotUsed(type)) const
{
using InputArrayType = vtkm::cont::ArrayHandleIndex;
using ResultArrayType = vtkm::cont::ArrayHandle<CastFromType>;
InputArrayType input(ARRAY_SIZE);
ResultArrayType result;
vtkm::cont::ArrayHandleCast<vtkm::Id, ResultArrayType> castArray =
vtkm::cont::make_ArrayHandleCast<CastFromType>(result);
vtkm::worklet::DispatcherMapField<PassThrough> dispatcher;
dispatcher.Invoke(input, castArray);
vtkm::cont::printSummary_ArrayHandle(castArray, std::cout);
std::cout << std::endl;
// verify results
vtkm::Id length = ARRAY_SIZE;
for (vtkm::Id i = 0; i < length; ++i)
{
VTKM_TEST_ASSERT(input.GetPortalConstControl().Get(i) ==
static_cast<vtkm::Id>(result.GetPortalConstControl().Get(i)),
"Casting ArrayHandle Failed");
}
}
};
template <vtkm::IdComponent NUM_COMPONENTS>
struct TestGroupVecAsInput
{
@ -1284,6 +1315,11 @@ private:
vtkm::testing::Testing::TryTypes(
TestingFancyArrayHandles<DeviceAdapterTag>::TestCastAsInput(), CastTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleCast as Output" << std::endl;
vtkm::testing::Testing::TryTypes(
TestingFancyArrayHandles<DeviceAdapterTag>::TestCastAsOutput(), CastTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleGroupVec<3> as Input" << std::endl;
vtkm::testing::Testing::TryTypes(

@ -109,6 +109,15 @@ struct TestArrayHandleCast
RunTest(array);
RunTest(MakeTestVariantArrayHandle(array));
}
template <typename T, vtkm::IdComponent N>
void operator()(vtkm::Vec<T, N>) const
{
auto array = vtkm::cont::make_ArrayHandleCast<vtkm::Vec<T, N>>(
RandomArrayHandle<vtkm::Vec<vtkm::Int8, N>>::Make(ArraySize));
RunTest(array);
RunTest(MakeTestVariantArrayHandle(array));
}
};
struct TestArrayHandleCompositeVector