Add copy methods to UnknownArrayHandle

`vtkm::cont::UnknownArrayHandle` now provides a set of method that
allows you to copy data from one `UnknownArrayHandle` to another. The
first method, `DeepCopyFrom`, takes a source `UnknownArrayHandle` and
deep copies the data to the called one. If the `UnknownArrayHandle`
already points to a real `ArrayHandle`, the data is copied into that
`ArrayHandle`. If the `UnknownArrayHandle` does not point to an existing
`ArrayHandle`, then a new `ArrayHandleBasic` with the same value type as
the source is created and copied into.

The second method, `CopyShallowIfPossibleFrom` behaves similarly to
`DeepCopyFrom` except that it will perform a shallow copy if possible.
That is, if the target `UnknownArrayHandle` points to an `ArrayHandle`
of the same type as the source `UnknownArrayHandle`, then a shallow copy
occurs and the underlying `ArrayHandle` will point to the source. If the
types differ, then a deep copy is performed. If the target
`UnknownArrayHandle` does not point to an `ArrayHandle`, then the
behavior is the same as the `=` operator.

One of the intentions of these new methods is to allow you to copy
arrays without using a device compiler (e.g. `nvcc`). Calling
`ArrayCopy` requires you to include the `ArrayCopy.h` header file, and
that in turn requires device adapter algorithms. These methods insulate
you from these.
This commit is contained in:
Kenneth Moreland 2021-09-28 10:46:41 -06:00
parent 7aae612d95
commit d1160638b7
7 changed files with 245 additions and 0 deletions

@ -0,0 +1,24 @@
# Added copy methods to `UnknownArrayHandle`
`vtkm::cont::UnknownArrayHandle` now provides a set of method that allows
you to copy data from one `UnknownArrayHandle` to another. The first
method, `DeepCopyFrom`, takes a source `UnknownArrayHandle` and deep copies
the data to the called one. If the `UnknownArrayHandle` already points to a
real `ArrayHandle`, the data is copied into that `ArrayHandle`. If the
`UnknownArrayHandle` does not point to an existing `ArrayHandle`, then a
new `ArrayHandleBasic` with the same value type as the source is created
and copied into.
The second method, `CopyShallowIfPossibleFrom` behaves similarly to
`DeepCopyFrom` except that it will perform a shallow copy if possible. That
is, if the target `UnknownArrayHandle` points to an `ArrayHandle` of the
same type as the source `UnknownArrayHandle`, then a shallow copy occurs
and the underlying `ArrayHandle` will point to the source. If the types
differ, then a deep copy is performed. If the target `UnknownArrayHandle`
does not point to an `ArrayHandle`, then the behavior is the same as the
`=` operator.
One of the intentions of these new methods is to allow you to copy arrays
without using a device compiler (e.g. `nvcc`). Calling `ArrayCopy` requires
you to include the `ArrayCopy.h` header file, and that in turn requires
device adapter algorithms. These methods insulate you from these.

@ -12,6 +12,8 @@
#include <vtkm/cont/DeviceAdapterList.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/cont/internal/ArrayCopyUnknown.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace
@ -163,5 +165,22 @@ void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
DoUnknownArrayCopy(source, destination);
}
namespace internal
{
void ArrayCopyUnknown(const vtkm::cont::UnknownArrayHandle& source,
vtkm::cont::UnknownArrayHandle& destination)
{
vtkm::cont::ArrayCopy(source, destination);
}
void ArrayCopyUnknown(const vtkm::cont::UnknownArrayHandle& source,
const vtkm::cont::UnknownArrayHandle& destination)
{
vtkm::cont::ArrayCopy(source, destination);
}
} // namespace vtkm::cont::internal
} // namespace vtkm::cont
} // namespace vtkm

@ -22,6 +22,8 @@
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/UncertainArrayHandle.h>
#include <vtkm/cont/internal/ArrayCopyUnknown.h>
#include <sstream>
namespace
@ -271,6 +273,48 @@ VTKM_CONT void UnknownArrayHandle::Allocate(vtkm::Id numValues, vtkm::CopyFlag p
this->Allocate(numValues, preserve, token);
}
VTKM_CONT void UnknownArrayHandle::DeepCopyFrom(const vtkm::cont::UnknownArrayHandle& source)
{
vtkm::cont::internal::ArrayCopyUnknown(source, *this);
}
VTKM_CONT void UnknownArrayHandle::DeepCopyFrom(const vtkm::cont::UnknownArrayHandle& source) const
{
vtkm::cont::internal::ArrayCopyUnknown(source, *this);
}
VTKM_CONT
void UnknownArrayHandle::CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle& source)
{
if (!this->IsValid())
{
*this = source;
}
const_cast<const UnknownArrayHandle*>(this)->CopyShallowIfPossible(source);
}
VTKM_CONT
void UnknownArrayHandle::CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle& source) const
{
if (!this->IsValid())
{
throw vtkm::cont::ErrorBadValue(
"Attempty to copy to a constant UnknownArrayHandle with no valid array.");
}
if (source.IsValueTypeImpl(this->Container->ValueType) &&
source.IsStorageTypeImpl(this->Container->StorageType))
{
this->Container->ShallowCopy(source.Container->ArrayHandlePointer,
this->Container->ArrayHandlePointer);
}
else
{
this->DeepCopyFrom(source);
}
}
VTKM_CONT void UnknownArrayHandle::ReleaseResourcesExecution() const
{
if (this->Container)

@ -104,6 +104,15 @@ static void UnknownAHAllocate(void* mem,
arrayHandle->Allocate(numValues, preserve, token);
}
template <typename T, typename S>
static void UnknownAHShallowCopy(const void* sourceMem, void* destinationMem)
{
using AH = vtkm::cont::ArrayHandle<T, S>;
const AH* source = reinterpret_cast<const AH*>(sourceMem);
AH* destination = reinterpret_cast<AH*>(destinationMem);
*destination = *source;
}
template <typename T, typename S>
static std::vector<vtkm::cont::internal::Buffer>
UnknownAHExtractComponent(void* mem, vtkm::IdComponent componentIndex, vtkm::CopyFlag allowCopy)
@ -212,6 +221,9 @@ struct VTKM_CONT_EXPORT UnknownAHContainer
using AllocateType = void(void*, vtkm::Id, vtkm::CopyFlag, vtkm::cont::Token&);
AllocateType* Allocate;
using ShallowCopyType = void(const void*, void*);
ShallowCopyType* ShallowCopy;
using ExtractComponentType = std::vector<vtkm::cont::internal::Buffer>(void*,
vtkm::IdComponent,
vtkm::CopyFlag);
@ -336,6 +348,7 @@ inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle<T, S
, NumberOfComponents(detail::UnknownAHNumberOfComponents<T>)
, NumberOfComponentsFlat(detail::UnknownAHNumberOfComponentsFlat<T>)
, Allocate(detail::UnknownAHAllocate<T, S>)
, ShallowCopy(detail::UnknownAHShallowCopy<T, S>)
, ExtractComponent(detail::UnknownAHExtractComponent<T, S>)
, ReleaseResources(detail::UnknownAHReleaseResources<T, S>)
, ReleaseResourcesExecution(detail::UnknownAHReleaseResourcesExecution<T, S>)
@ -662,6 +675,54 @@ public:
result = this->AsArrayHandle<MultiplexerType>();
}
/// \brief Deep copies data from another `UnknownArrayHandle`.
///
/// This method takes an `UnknownArrayHandle` and deep copies data from it.
///
/// If this object does not point to an existing `ArrayHandle`, a new `ArrayHandleBasic`
/// with the same value type of the `source` is created.
///
void DeepCopyFrom(const vtkm::cont::UnknownArrayHandle& source);
/// \brief Deep copies data from another `UnknownArrayHandle`.
///
/// This method takes an `UnknownArrayHandle` and deep copies data from it.
///
/// If this object does not point to an existing `ArrayHandle`, this const version
/// of `DeepCopyFrom` throws an exception.
///
void DeepCopyFrom(const vtkm::cont::UnknownArrayHandle& source) const;
/// \brief Attempts a shallow copy of an array or a deep copy if that is not possible.
///
/// This method takes an `UnknownArrayHandle` and attempts to perform a shallow copy.
/// This shallow copy occurs if this object points to an `ArrayHandle` of the same type
/// or does not point to any `ArrayHandle` at all. If this is not possible, then
/// the array is deep copied.
///
/// This method is roughly equivalent to the `ArrayCopyShallowIfPossible` function
/// (defined in `vtkm/cont/ArrayCopy.h`). However, this method can be used without
/// having to use a device compiler (whereas `ArrayCopyShallowIfPossible` does require
/// a device device compiler).
///
void CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle& source);
/// \brief Attempts a shallow copy of an array or a deep copy if that is not possible.
///
/// This method takes an `UnknownArrayHandle` and attempts to perform a shallow copy.
/// This shallow copy occurs if this object points to an `ArrayHandle` of the same type.
/// If the types are incompatible, then the array is deep copied.
///
/// If this object does not point to an existing `ArrayHandle`, this const version
/// of `CopyShallowIfPossible` throws an exception.
///
/// This method is roughly equivalent to the `ArrayCopyShallowIfPossible` function
/// (defined in `vtkm/cont/ArrayCopy.h`). However, this method can be used without
/// having to use a device compiler (whereas `ArrayCopyShallowIfPossible` does require
/// a device device compiler).
///
void CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle& source) const;
/// \brief Extract a component of the array.
///
/// This method returns an array that holds the data for a given flat component of the data.

@ -0,0 +1,38 @@
//============================================================================
// 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_internal_ArrayCopyUnknown_h
#define vtk_m_cont_internal_ArrayCopyUnknown_h
#include <vtkm/cont/UnknownArrayHandle.h>
#include <vtkm/cont/vtkm_cont_export.h>
namespace vtkm
{
namespace cont
{
namespace internal
{
/// Same as `ArrayCopy` with `UnknownArrayHandle` except that it can be used without
/// using a device compiler.
///
VTKM_CONT_EXPORT void ArrayCopyUnknown(const vtkm::cont::UnknownArrayHandle& source,
vtkm::cont::UnknownArrayHandle& destination);
VTKM_CONT_EXPORT void ArrayCopyUnknown(const vtkm::cont::UnknownArrayHandle& source,
const vtkm::cont::UnknownArrayHandle& destination);
} // namespace vtkm::cont::internal
} // namespace vtkm::cont
} // namespace vtkm
#endif //vtk_m_cont_internal_ArrayCopyUnknown_h

@ -9,6 +9,7 @@
##============================================================================
set(headers
ArrayCopyUnknown.h
ArrayHandleDeprecated.h
ArrayHandleExecutionManager.h
ArrayPortalFromIterators.h

@ -118,6 +118,64 @@ void TryCopy()
vtkm::cont::ArrayCopy(input, output);
TestValues(input, output);
}
// Test the copy methods in UnknownArrayHandle. Although this would be appropriate in
// UnitTestUnknownArrayHandle, it is easier to test copies here.
{
std::cout << "unknown.DeepCopyFrom(same type)" << std::endl;
vtkm::cont::ArrayHandle<ValueType> input = MakeInputArray<ValueType>();
vtkm::cont::ArrayHandle<ValueType> outputArray;
vtkm::cont::UnknownArrayHandle(outputArray).DeepCopyFrom(input);
// Should be different arrays with same content.
VTKM_TEST_ASSERT(input != outputArray);
TestValues(input, outputArray);
vtkm::cont::UnknownArrayHandle outputUnknown;
outputUnknown.DeepCopyFrom(input);
// Should be different arrays with same content.
VTKM_TEST_ASSERT(input != outputUnknown.AsArrayHandle<vtkm::cont::ArrayHandle<ValueType>>());
TestValues(input, outputUnknown);
}
{
std::cout << "unknown.DeepCopyFrom(different type)" << std::endl;
vtkm::cont::ArrayHandle<vtkm::UInt8> input = MakeInputArray<vtkm::UInt8>();
vtkm::cont::ArrayHandle<ValueType> outputArray;
vtkm::cont::UnknownArrayHandle(outputArray).DeepCopyFrom(input);
TestValues(input, outputArray);
outputArray.ReleaseResources();
vtkm::cont::UnknownArrayHandle outputUnknown(outputArray);
outputUnknown.DeepCopyFrom(input);
TestValues(input, outputUnknown);
}
{
std::cout << "unknown.CopyShallowIfPossible(same type)" << std::endl;
vtkm::cont::ArrayHandle<ValueType> input = MakeInputArray<ValueType>();
vtkm::cont::UnknownArrayHandle outputUnknown;
outputUnknown.CopyShallowIfPossible(input);
VTKM_TEST_ASSERT(input == outputUnknown.AsArrayHandle<vtkm::cont::ArrayHandle<ValueType>>());
vtkm::cont::ArrayHandle<ValueType> outputArray;
outputUnknown = outputArray;
outputUnknown.CopyShallowIfPossible(input);
outputUnknown.AsArrayHandle(outputArray);
VTKM_TEST_ASSERT(input == outputArray);
}
{
std::cout << "unknown.CopyShallowIfPossible(different type)" << std::endl;
vtkm::cont::ArrayHandle<vtkm::UInt8> input = MakeInputArray<vtkm::UInt8>();
vtkm::cont::ArrayHandle<ValueType> outputArray;
vtkm::cont::UnknownArrayHandle(outputArray).CopyShallowIfPossible(input);
TestValues(input, outputArray);
outputArray.ReleaseResources();
vtkm::cont::UnknownArrayHandle outputUnknown(outputArray);
outputUnknown.CopyShallowIfPossible(input);
TestValues(input, outputUnknown);
}
}
void TryArrayCopyShallowIfPossible()