mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-08 13:23:51 +00:00
Add ability to resize ArrayHandleStride
This feature enables the ability to anonomously create an array (such as with `UnknownArrayHandle::NewInstance()`) and then use that as an output array. Although resizing `ArrayHandleStride` is a little wonky, it allows worklets to resize them after creation rather than having to know what size to make and allocating the array.
This commit is contained in:
parent
146b051436
commit
2061e95efe
18
docs/changelog/resize-extracted-component.md
Normal file
18
docs/changelog/resize-extracted-component.md
Normal file
@ -0,0 +1,18 @@
|
||||
# Added ability to resize strided arrays from ArrayExtractComponent
|
||||
|
||||
Previously, it was not possible to resize an `ArrayHandleStride` because
|
||||
the operation is a bit ambiguous. The actual array is likely to be padded
|
||||
by some amount, and there could be an unknown amount of space skipped at
|
||||
the beginning.
|
||||
|
||||
However, there is a good reason to want to resize `ArrayHandleStride`. This
|
||||
is the array used to implement the `ArrayExtractComponent` feature, and
|
||||
this in turn is used when extracting arrays from an `UnknownArrayHandle`
|
||||
whether independent or as an `ArrayHandleRecombineVec`.
|
||||
|
||||
The problem really happens when you create an array of an unknown type in
|
||||
an `UnknownArrayHandle` (such as with `NewInstance`) and then use that as
|
||||
an output to a worklet. Sure, you could use `ArrayHandle::Allocate` to
|
||||
resize before getting the array, but that is awkward for programers.
|
||||
Instead, allow the extracted arrays to be resized as normal output arrays
|
||||
would be.
|
@ -158,8 +158,6 @@ class VTKM_ALWAYS_EXPORT Storage<T, vtkm::cont::StorageTagStride>
|
||||
using StrideInfo = vtkm::internal::ArrayStrideInfo;
|
||||
|
||||
public:
|
||||
VTKM_STORAGE_NO_RESIZE;
|
||||
|
||||
using ReadPortalType = vtkm::internal::ArrayPortalStrideRead<T>;
|
||||
using WritePortalType = vtkm::internal::ArrayPortalStrideWrite<T>;
|
||||
|
||||
@ -174,6 +172,85 @@ public:
|
||||
return GetInfo(buffers).NumberOfValues;
|
||||
}
|
||||
|
||||
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
|
||||
const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
||||
vtkm::CopyFlag preserve,
|
||||
vtkm::cont::Token& token)
|
||||
{
|
||||
StrideInfo& info = GetInfo(buffers);
|
||||
|
||||
if (info.NumberOfValues == numValues)
|
||||
{
|
||||
// Array resized to current size. Don't need to do anything.
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the end index after dealing with the divsor and modulo.
|
||||
auto lengthDivMod = [info](vtkm::Id length) -> vtkm::Id {
|
||||
vtkm::Id resultLength = ((length - 1) / info.Divisor) + 1;
|
||||
if ((info.Modulo > 0) && (info.Modulo < resultLength))
|
||||
{
|
||||
resultLength = info.Modulo;
|
||||
}
|
||||
return resultLength;
|
||||
};
|
||||
vtkm::Id lastStridedIndex = lengthDivMod(numValues);
|
||||
|
||||
vtkm::Id originalStride;
|
||||
vtkm::Id originalOffset;
|
||||
if (info.Stride > 0)
|
||||
{
|
||||
originalStride = info.Stride;
|
||||
originalOffset = info.Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The stride is negative, which means we are counting backward. Here we have to be careful
|
||||
// about the offset, which should move to push to the end of the array. We also need to
|
||||
// be careful about multiplying by the stride.
|
||||
originalStride = -info.Stride;
|
||||
|
||||
vtkm::Id originalSize = lengthDivMod(info.NumberOfValues);
|
||||
|
||||
// Because the stride is negative, we expect the offset to be at the end of the array.
|
||||
// We will call the "real" offset the distance from that end.
|
||||
originalOffset = originalSize - info.Offset - 1;
|
||||
}
|
||||
|
||||
// If the offset is more than the stride, that means there are values skipped at the
|
||||
// beginning of the array, and it is impossible to know exactly how many. In this case,
|
||||
// we cannot know how to resize. (If this is an issue, we will have to change
|
||||
// `ArrayHandleStride` to take resizing parameters.)
|
||||
if (originalOffset >= originalStride)
|
||||
{
|
||||
if (numValues == 0)
|
||||
{
|
||||
// Array resized to zero. This can happen when releasing resources.
|
||||
// Should we try to clear out the buffers, or avoid that for messing up shared buffers?
|
||||
return;
|
||||
}
|
||||
throw vtkm::cont::ErrorBadAllocation(
|
||||
"Cannot resize stride array with offset greater than stride (start of stride unknown).");
|
||||
}
|
||||
|
||||
// lastIndex should be the index in the source array after each stride block. Assuming the
|
||||
// offset is inside the first stride, this should be the end of the array regardless of
|
||||
// offset.
|
||||
vtkm::Id lastIndex = lastStridedIndex * originalStride;
|
||||
|
||||
buffers[1].SetNumberOfBytes(
|
||||
vtkm::internal::NumberOfValuesToNumberOfBytes<T>(lastIndex), preserve, token);
|
||||
info.NumberOfValues = numValues;
|
||||
|
||||
if (info.Stride < 0)
|
||||
{
|
||||
// As described above, when the stride is negative, we are counting backward. This means
|
||||
// that the offset is actually relative to the end, so we need to adjust it to the new
|
||||
// end of the array.
|
||||
info.Offset = lastIndex - originalOffset - 1;
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_CONT static void Fill(const std::vector<vtkm::cont::internal::Buffer>&,
|
||||
const T&,
|
||||
vtkm::Id,
|
||||
|
@ -73,7 +73,6 @@ void CheckOutputArray(const vtkm::cont::ArrayHandle<T, S>& originalArray)
|
||||
//vtkm::cont::printSummary_ArrayHandle(originalArray, std::cout);
|
||||
|
||||
vtkm::cont::ArrayHandle<T, S> outputArray;
|
||||
outputArray.Allocate(originalArray.GetNumberOfValues());
|
||||
|
||||
using FlatVec = vtkm::VecFlat<T>;
|
||||
using ComponentType = typename FlatVec::ComponentType;
|
||||
@ -84,6 +83,7 @@ void CheckOutputArray(const vtkm::cont::ArrayHandle<T, S>& originalArray)
|
||||
vtkm::cont::ArrayExtractComponent(originalArray, numComponents - componentId - 1);
|
||||
vtkm::cont::ArrayHandleStride<ComponentType> outComponentArray =
|
||||
vtkm::cont::ArrayExtractComponent(outputArray, componentId, vtkm::CopyFlag::Off);
|
||||
outComponentArray.Allocate(originalArray.GetNumberOfValues());
|
||||
|
||||
auto inPortal = inComponentArray.ReadPortal();
|
||||
auto outPortal = outComponentArray.WritePortal();
|
||||
@ -173,7 +173,12 @@ void DoTest()
|
||||
auto compositeArray = vtkm::cont::make_ArrayHandleCompositeVector(array0, array1);
|
||||
CheckOutputArray(compositeArray);
|
||||
|
||||
CheckOutputArray(vtkm::cont::make_ArrayHandleExtractComponent(compositeArray, 1));
|
||||
// Note that when the extracted component array gets allocated, it only allocates the
|
||||
// array it was given. This is a weird case when using `ArrayHandleExtractComponent`
|
||||
// on something that has multiple arrays as input. It works fine if all components get
|
||||
// extracted and updated, but can cause issues if only one is resized. In this case
|
||||
// just test the input.
|
||||
CheckInputArray(vtkm::cont::make_ArrayHandleExtractComponent(compositeArray, 1));
|
||||
}
|
||||
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user