Specify end position when filling values in Buffer

This allows us to support `Fill` in `ArrayHandleView` and
`ArrayHandleReverse`.
This commit is contained in:
Kenneth Moreland 2022-01-11 07:15:41 -07:00
parent 7a4cbaf105
commit d7b4390d15
24 changed files with 138 additions and 59 deletions

@ -558,7 +558,7 @@ public:
if (startIndex < numberOfValues)
{
this->Fill(fillValue, startIndex, token);
this->Fill(fillValue, startIndex, numberOfValues, token);
}
}
@ -580,20 +580,26 @@ public:
/// @{
/// \brief Fills the array with a given value.
///
/// After calling this method, every entry in the array from `startIndex` to the
/// end of the array is set to `fillValue`. If `startIndex` is not specified, then
/// every entry is set to the fill value.
/// After calling this method, every entry in the array from `startIndex` to `endIndex`.
/// of the array is set to `fillValue`. If `startIndex` or `endIndex` is not specified,
/// then the fill happens from the begining or end, respectively.
///
VTKM_CONT void Fill(const ValueType& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token) const
{
StorageType::Fill(this->GetBuffers(), fillValue, startIndex, token);
StorageType::Fill(this->GetBuffers(), fillValue, startIndex, endIndex, token);
}
VTKM_CONT void Fill(const ValueType& fillValue, vtkm::Id startIndex, vtkm::Id endIndex) const
{
vtkm::cont::Token token;
this->Fill(fillValue, startIndex, endIndex, token);
}
VTKM_CONT void Fill(const ValueType& fillValue, vtkm::Id startIndex = 0) const
{
vtkm::cont::Token token;
this->Fill(fillValue, startIndex, token);
this->Fill(fillValue, startIndex, this->GetNumberOfValues(), token);
}
/// @}

@ -55,11 +55,13 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
const T& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token)
{
constexpr vtkm::BufferSizeType fillValueSize =
static_cast<vtkm::BufferSizeType>(sizeof(fillValue));
buffers[0].Fill(&fillValue, fillValueSize, startIndex * fillValueSize, token);
buffers[0].Fill(
&fillValue, fillValueSize, startIndex * fillValueSize, endIndex * fillValueSize, token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,

@ -113,19 +113,27 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
bool fillValue,
vtkm::Id startBit,
vtkm::Id endBit,
vtkm::cont::Token& token)
{
constexpr vtkm::BufferSizeType wordTypeSize =
static_cast<vtkm::BufferSizeType>(sizeof(WordType));
if ((startBit % (wordTypeSize * CHAR_BIT)) == 0)
constexpr vtkm::BufferSizeType wordNumBits = wordTypeSize * CHAR_BIT;
// Special case where filling to end of array.
vtkm::Id totalBitsInArray = GetNumberOfValues(buffers);
if (endBit >= totalBitsInArray)
{
endBit = ((totalBitsInArray + (wordNumBits - 1)) / wordNumBits) * wordNumBits;
}
if (((startBit % wordNumBits) == 0) && ((endBit % wordNumBits) == 0))
{
WordType fillWord = (fillValue ? ~WordType{ 0 } : WordType{ 0 });
buffers[0].Fill(&fillWord, wordTypeSize, startBit / CHAR_BIT, token);
buffers[0].Fill(&fillWord, wordTypeSize, startBit / CHAR_BIT, endBit / CHAR_BIT, token);
}
else if ((startBit % CHAR_BIT) == 0)
else if (((startBit % CHAR_BIT) == 0) && ((endBit % CHAR_BIT) == 0))
{
vtkm::UInt8 fillWord = (fillValue ? ~vtkm::UInt8{ 0 } : vtkm::UInt8{ 0 });
buffers[0].Fill(&fillWord, 1, startBit / CHAR_BIT, token);
buffers[0].Fill(&fillWord, 1, startBit / CHAR_BIT, endBit / CHAR_BIT, token);
}
else
{

@ -251,16 +251,20 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
const vtkm::Vec<T, 3>& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token)
{
if (startIndex != 0)
if ((startIndex != 0) || (endIndex != GetNumberOfValues(buffers)))
{
throw vtkm::cont::ErrorBadValue(
"Fill for ArrayHandleCartesianProduct must have startIndex == 0");
"Fill for ArrayHandleCartesianProduct can only be used to fill entire array.");
}
Storage1::Fill(Buffers1(buffers), fillValue[0], startIndex, token);
Storage2::Fill(Buffers2(buffers), fillValue[1], startIndex, token);
Storage3::Fill(Buffers3(buffers), fillValue[2], startIndex, token);
Storage1::Fill(
Buffers1(buffers), fillValue[0], 0, Storage1::GetNumberOfValues(Buffers1(buffers)), token);
Storage2::Fill(
Buffers2(buffers), fillValue[1], 0, Storage2::GetNumberOfValues(Buffers2(buffers)), token);
Storage3::Fill(
Buffers3(buffers), fillValue[2], 0, Storage3::GetNumberOfValues(Buffers3(buffers)), token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,

@ -273,11 +273,15 @@ private:
vtkm::cont::internal::Buffer* buffers,
const ValueType& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token)
{
auto init_list = { (
vtkm::tuple_element_t<Is, StorageTuple>::Fill(
Buffers<Is>(buffers), fillValue[static_cast<vtkm::IdComponent>(Is)], startIndex, token),
vtkm::tuple_element_t<Is, StorageTuple>::Fill(Buffers<Is>(buffers),
fillValue[static_cast<vtkm::IdComponent>(Is)],
startIndex,
endIndex,
token),
false)... };
(void)init_list;
}
@ -324,9 +328,10 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
const ValueType& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token)
{
FillImpl(IndexList{}, buffers, fillValue, startIndex, token);
FillImpl(IndexList{}, buffers, fillValue, startIndex, endIndex, token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,

@ -205,17 +205,23 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
const T& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token)
{
vtkm::Id size1 = SourceStorage1::GetNumberOfValues(Buffers1(buffers));
if (startIndex < size1)
if ((startIndex < size1) && (endIndex <= size1))
{
SourceStorage1::Fill(Buffers1(buffers), fillValue, startIndex, token);
SourceStorage2::Fill(Buffers2(buffers), fillValue, 0, token);
SourceStorage1::Fill(Buffers1(buffers), fillValue, startIndex, endIndex, token);
}
else
else if (startIndex < size1) // && (endIndex > size1)
{
SourceStorage2::Fill(Buffers2(buffers), fillValue, startIndex - size1, token);
SourceStorage1::Fill(Buffers1(buffers), fillValue, startIndex, size1, token);
SourceStorage2::Fill(Buffers2(buffers), fillValue, 0, endIndex - size1, token);
}
else // startIndex >= size1
{
SourceStorage2::Fill(
Buffers2(buffers), fillValue, startIndex - size1, endIndex - size1, token);
}
}

@ -122,6 +122,7 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer*,
const ValueType&,
vtkm::Id,
vtkm::Id,
vtkm::cont::Token&)
{
// Fill is a NO-OP.

@ -132,6 +132,7 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer*,
const ValueType&,
vtkm::Id,
vtkm::Id,
vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadType("Fill not supported for ArrayHandleExtractComponent.");

@ -150,6 +150,7 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer*,
const ValueType&,
vtkm::Id,
vtkm::Id,
vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadType("Fill not supported for ArrayHandleGroupVec.");

@ -161,6 +161,7 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer*,
const vtkm::VecFromPortal<ComponentsPortal>&,
vtkm::Id,
vtkm::Id,
vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadType("Fill not supported for ArrayHandleGroupVecVariable.");

@ -177,9 +177,10 @@ struct MultiplexerFillFunctor
vtkm::cont::internal::Buffer* buffers,
const ValueType& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token) const
{
StorageType::Fill(buffers, fillValue, startIndex, token);
StorageType::Fill(buffers, fillValue, startIndex, endIndex, token);
}
};
@ -272,10 +273,15 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
const ValueType& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token)
{
Variant(buffers).CastAndCall(
detail::MultiplexerFillFunctor{}, ArrayBuffers(buffers), fillValue, startIndex, token);
Variant(buffers).CastAndCall(detail::MultiplexerFillFunctor{},
ArrayBuffers(buffers),
fillValue,
startIndex,
endIndex,
token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,

@ -140,7 +140,11 @@ public:
return IndexStorage::GetNumberOfValues(IndexBuffers(buffers));
}
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer*, const T&, vtkm::Id, vtkm::cont::Token&)
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer*,
const T&,
vtkm::Id,
vtkm::Id,
vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadType("Fill not supported for ArrayHandlePermutation.");
}

@ -445,6 +445,7 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer*,
const vtkm::internal::RecombineVec<ReadWritePortal>&,
vtkm::Id,
vtkm::Id,
vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadType("Fill not supported for ArrayHandleRecombineVec.");

@ -149,16 +149,11 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
const T& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token)
{
if (startIndex == 0)
{
SourceStorage::Fill(buffers, fillValue, 0, token);
}
else
{
throw vtkm::cont::ErrorBadValue("ArrayHandleReverse cannot Fill partial array.");
}
vtkm::Id numValues = GetNumberOfValues(buffers);
SourceStorage::Fill(buffers, fillValue, numValues - endIndex, numValues - startIndex, token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,

@ -165,15 +165,17 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
const ValueType& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token)
{
constexpr vtkm::BufferSizeType sourceSize =
static_cast<vtkm::BufferSizeType>(sizeof(ComponentType));
vtkm::BufferSizeType startByte = startIndex * sourceSize;
vtkm::BufferSizeType endByte = endIndex * sourceSize;
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; ++componentIndex)
{
ComponentType source = fillValue[componentIndex];
buffers[componentIndex].Fill(&source, sourceSize, startByte, token);
buffers[componentIndex].Fill(&source, sourceSize, startByte, endByte, token);
}
}

@ -175,7 +175,11 @@ public:
return GetInfo(buffers).NumberOfValues;
}
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer*, const T&, vtkm::Id, vtkm::cont::Token&)
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer*,
const T&,
vtkm::Id,
vtkm::Id,
vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadType("Fill not supported for ArrayHandleStride.");
}

@ -168,9 +168,18 @@ public:
return ReadPortalType(SourceStorage::CreateReadPortal(buffers + 1, device, token), indices);
}
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer*, const T&, vtkm::Id, vtkm::cont::Token&)
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
const T& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token)
{
throw vtkm::cont::ErrorBadType("Fill not supported for ArrayHandleView.");
vtkm::internal::ViewIndices indices = buffers[0].GetMetaData<vtkm::internal::ViewIndices>();
vtkm::Id adjustedStartIndex = startIndex + indices.StartIndex;
vtkm::Id adjustedEndIndex = (endIndex < indices.NumberOfValues)
? endIndex + indices.StartIndex
: indices.NumberOfValues + indices.StartIndex;
SourceStorage::Fill(buffers, fillValue, adjustedStartIndex, adjustedEndIndex, token);
}
VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,

@ -184,10 +184,11 @@ public:
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
const ValueType& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token)
{
FirstStorage::Fill(FirstArrayBuffers(buffers), fillValue.first, startIndex, token);
SecondStorage::Fill(SecondArrayBuffers(buffers), fillValue.second, startIndex, token);
FirstStorage::Fill(FirstArrayBuffers(buffers), fillValue.first, startIndex, endIndex, token);
SecondStorage::Fill(SecondArrayBuffers(buffers), fillValue.second, startIndex, endIndex, token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,

@ -74,7 +74,7 @@ void BitField::FillImpl(const void* word,
vtkm::BufferSizeType wordSize,
vtkm::cont::Token& token) const
{
this->Buffer.Fill(word, wordSize, 0, token);
this->Buffer.Fill(word, wordSize, 0, this->Buffer.GetNumberOfBytes(), token);
}
void BitField::ReleaseResourcesExecution()

@ -134,11 +134,12 @@ public:
/// \brief Returns the number of entries allocated in the array.
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers);
/// \brief Fills the array with the given value starting at the given index.
/// \brief Fills the array with the given value starting and ending at the given indices.
///
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
const ValueType& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token);
/// \brief Create a read-only portal on the specified device.
@ -192,6 +193,7 @@ struct StorageTraits<vtkm::cont::internal::Storage<T, S>>
vtkm::cont::internal::Buffer*, \
const typename vtkm::cont::internal::StorageTraits<Storage>::ValueType&, \
vtkm::Id, \
vtkm::Id, \
vtkm::cont::Token&) \
{ \
throw vtkm::cont::ErrorBadAllocation( \

@ -202,6 +202,7 @@ template <typename Device>
void FillBuffer(const vtkm::cont::internal::Buffer& target,
const vtkm::cont::internal::Buffer& source,
vtkm::BufferSizeType start,
vtkm::BufferSizeType end,
Device device,
vtkm::cont::Token& token)
{
@ -217,8 +218,16 @@ void FillBuffer(const vtkm::cont::internal::Buffer& target,
}
VTKM_ASSERT((targetSize % sourceSize) == 0);
VTKM_ASSERT((start % sourceSize) == 0);
VTKM_ASSERT((end % sourceSize) == 0);
VTKM_ASSERT(end <= targetSize);
VTKM_ASSERT(end >= start);
if (end <= start)
{
// Nothing to set.
return;
}
vtkm::Id numSourceRepetitions = (targetSize - start) / sourceSize;
vtkm::Id numSourceRepetitions = (end - start) / sourceSize;
if ((sourceSize >= 8) && ((sourceSize % 8) == 0))
{
@ -1107,6 +1116,7 @@ vtkm::cont::internal::BufferInfo Buffer::GetDeviceBufferInfo(
void Buffer::Fill(const void* source,
vtkm::BufferSizeType sourceSize,
vtkm::BufferSizeType start,
vtkm::BufferSizeType end,
vtkm::cont::Token& token) const
{
vtkm::cont::internal::Buffer sourceBuffer;
@ -1122,7 +1132,7 @@ void Buffer::Fill(const void* source,
bool success = vtkm::cont::TryExecute([&](auto device) {
if (this->IsAllocatedOnDevice(device))
{
FillBuffer(*this, sourceBuffer, start, device, token);
FillBuffer(*this, sourceBuffer, start, end, device, token);
return true;
}
else
@ -1135,7 +1145,7 @@ void Buffer::Fill(const void* source,
{
// Likely the data was not on any device. Fill on any device.
vtkm::cont::TryExecute([&](auto device) {
FillBuffer(*this, sourceBuffer, start, device, token);
FillBuffer(*this, sourceBuffer, start, end, device, token);
return true;
});
}

@ -314,14 +314,15 @@ public:
///
/// Given a short `source` C array (defined on the host), sets all values in the buffer
/// to that source. The `sourceSize`, in bytes, is also specified. You also specify an
/// offset to where the fill should `start`. Values before the `start` are not affected.
/// offset to where the fill should `start` and `end`. Values before the `start` and
/// after the `end` are not affected.
///
/// Both the size of the buffer (i.e. `GetNumberOfBytes`) and the `start` must be
/// divisible by `sourceSize`.
/// Both `start` and `end` must be divisible by `sourceSize`.
///
VTKM_CONT void Fill(const void* source,
vtkm::BufferSizeType sourceSize,
vtkm::BufferSizeType start,
vtkm::BufferSizeType end,
vtkm::cont::Token& token) const;
VTKM_CONT bool operator==(const vtkm::cont::internal::Buffer& rhs) const

@ -186,17 +186,26 @@ void DoTest()
VTKM_TEST_ASSERT(buffer.IsAllocatedOnHost());
VTKM_TEST_ASSERT(!buffer.IsAllocatedOnDevice(device));
std::cout << "Fill end of buffer" << std::endl;
std::cout << "Fill buffer" << std::endl;
{
constexpr vtkm::BufferSizeType fillValueSize = static_cast<vtkm::BufferSizeType>(sizeof(T));
vtkm::cont::Token token;
T fillValue = 1.234f;
buffer.Fill(
&fillValue, static_cast<vtkm::BufferSizeType>(sizeof(fillValue)), BUFFER_SIZE / 2, token);
CheckPortal(MakePortal(buffer.ReadPointerHost(token), ARRAY_SIZE / 2));
T fillValue1 = 1.234f;
T fillValue2 = 5.678f;
buffer.Fill(&fillValue1, fillValueSize, 0, BUFFER_SIZE * 2, token);
buffer.Fill(&fillValue2, fillValueSize, BUFFER_SIZE / 2, BUFFER_SIZE, token);
const T* array = reinterpret_cast<const T*>(buffer.ReadPointerHost(token));
for (vtkm::Id index = (ARRAY_SIZE / 2); index < (ARRAY_SIZE * 2); ++index)
for (vtkm::Id index = 0; index < ARRAY_SIZE / 2; ++index)
{
VTKM_TEST_ASSERT(array[index] == fillValue);
VTKM_TEST_ASSERT(array[index] == fillValue1);
}
for (vtkm::Id index = ARRAY_SIZE / 2; index < ARRAY_SIZE; ++index)
{
VTKM_TEST_ASSERT(array[index] == fillValue2);
}
for (vtkm::Id index = ARRAY_SIZE; index < ARRAY_SIZE * 2; ++index)
{
VTKM_TEST_ASSERT(array[index] == fillValue1);
}
}

@ -94,9 +94,9 @@ void TestConcatenateFill()
VTKM_STATIC_ASSERT_MSG((ARRAY_SIZE % 2) == 0, "ARRAY_SIZE must be even for this test.");
concatArray.Fill(value0);
concatArray.Fill(value1, ARRAY_SIZE / 2);
concatArray.Fill(value2, 3 * ARRAY_SIZE / 2);
concatArray.Fill(value1, ARRAY_SIZE / 2, 3 * ARRAY_SIZE / 2);
concatArray.Fill(value0, 0, ARRAY_SIZE / 2);
vtkm::cont::printSummary_ArrayHandle(concatArray, std::cout, true);