Merge topic 'allocate-and-fill'

d7b4390d1 Specify end position when filling values in Buffer
7a4cbaf10 Suggestions during review by Gunther Weber
8e4fb7ebd Suppress unhelpful nvcc warning
bacca0693 Add Fill method for non-standard Storage
9da66ff32 Prefer ArrayHandle::Fill over Algorithm::Fill
f79cf1d5f Add BitField::Fill and BitField::AllocateAndFill
926164049 Add Fill and AllocateAndFill to ArrayHandle
0cf996f41 Add ability to fill values in a Buffer

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !2660
This commit is contained in:
Kenneth Moreland 2022-01-13 22:15:31 +00:00 committed by Kitware Robot
commit e8a6d37190
45 changed files with 912 additions and 100 deletions

@ -64,8 +64,7 @@ void BenchAddSeq(benchmark::State& state)
auto ones = vtkm::cont::make_ArrayHandleConstant<ValueType>(static_cast<ValueType>(1), numWrites);
vtkm::cont::ArrayHandle<ValueType> atomicArray;
vtkm::cont::Algorithm::Fill(
atomicArray, vtkm::TypeTraits<ValueType>::ZeroInitialization(), numValues);
atomicArray.AllocateAndFill(numValues, vtkm::TypeTraits<ValueType>::ZeroInitialization());
vtkm::cont::Invoker invoker{ device };
vtkm::cont::Timer timer{ device };
@ -115,7 +114,7 @@ void BenchAddSeqBaseline(benchmark::State& state)
auto ones = vtkm::cont::make_ArrayHandleConstant<ValueType>(static_cast<ValueType>(1), numWrites);
vtkm::cont::ArrayHandle<ValueType> array;
vtkm::cont::Algorithm::Fill(array, vtkm::TypeTraits<ValueType>::ZeroInitialization(), numValues);
array.AllocateAndFill(numValues, vtkm::TypeTraits<ValueType>::ZeroInitialization());
vtkm::cont::Invoker invoker{ device };
vtkm::cont::Timer timer{ device };
@ -175,8 +174,7 @@ void BenchAddStride(benchmark::State& state)
auto ones = vtkm::cont::make_ArrayHandleConstant<ValueType>(static_cast<ValueType>(1), numWrites);
vtkm::cont::ArrayHandle<ValueType> atomicArray;
vtkm::cont::Algorithm::Fill(
atomicArray, vtkm::TypeTraits<ValueType>::ZeroInitialization(), numValues);
atomicArray.AllocateAndFill(numValues, vtkm::TypeTraits<ValueType>::ZeroInitialization());
vtkm::cont::Invoker invoker{ device };
vtkm::cont::Timer timer{ device };
@ -235,7 +233,7 @@ void BenchAddStrideBaseline(benchmark::State& state)
auto ones = vtkm::cont::make_ArrayHandleConstant<ValueType>(static_cast<ValueType>(1), numWrites);
vtkm::cont::ArrayHandle<ValueType> array;
vtkm::cont::Algorithm::Fill(array, vtkm::TypeTraits<ValueType>::ZeroInitialization(), numValues);
array.AllocateAndFill(numValues, vtkm::TypeTraits<ValueType>::ZeroInitialization());
vtkm::cont::Invoker invoker{ device };
vtkm::cont::Timer timer{ device };
@ -289,8 +287,7 @@ void BenchCASSeq(benchmark::State& state)
auto ones = vtkm::cont::make_ArrayHandleConstant<ValueType>(static_cast<ValueType>(1), numWrites);
vtkm::cont::ArrayHandle<ValueType> atomicArray;
vtkm::cont::Algorithm::Fill(
atomicArray, vtkm::TypeTraits<ValueType>::ZeroInitialization(), numValues);
atomicArray.AllocateAndFill(numValues, vtkm::TypeTraits<ValueType>::ZeroInitialization());
vtkm::cont::Invoker invoker{ device };
vtkm::cont::Timer timer{ device };
@ -342,7 +339,7 @@ void BenchCASSeqBaseline(benchmark::State& state)
auto ones = vtkm::cont::make_ArrayHandleConstant<ValueType>(static_cast<ValueType>(1), numWrites);
vtkm::cont::ArrayHandle<ValueType> array;
vtkm::cont::Algorithm::Fill(array, vtkm::TypeTraits<ValueType>::ZeroInitialization(), numValues);
array.AllocateAndFill(numValues, vtkm::TypeTraits<ValueType>::ZeroInitialization());
vtkm::cont::Invoker invoker{ device };
vtkm::cont::Timer timer{ device };
@ -406,8 +403,7 @@ void BenchCASStride(benchmark::State& state)
auto ones = vtkm::cont::make_ArrayHandleConstant<ValueType>(static_cast<ValueType>(1), numWrites);
vtkm::cont::ArrayHandle<ValueType> atomicArray;
vtkm::cont::Algorithm::Fill(
atomicArray, vtkm::TypeTraits<ValueType>::ZeroInitialization(), numValues);
atomicArray.AllocateAndFill(numValues, vtkm::TypeTraits<ValueType>::ZeroInitialization());
vtkm::cont::Invoker invoker{ device };
vtkm::cont::Timer timer{ device };
@ -468,7 +464,7 @@ void BenchCASStrideBaseline(benchmark::State& state)
auto ones = vtkm::cont::make_ArrayHandleConstant<ValueType>(static_cast<ValueType>(1), numWrites);
vtkm::cont::ArrayHandle<ValueType> array;
vtkm::cont::Algorithm::Fill(array, vtkm::TypeTraits<ValueType>::ZeroInitialization(), numValues);
array.AllocateAndFill(numValues, vtkm::TypeTraits<ValueType>::ZeroInitialization());
vtkm::cont::Invoker invoker{ device };
vtkm::cont::Timer timer{ device };

@ -0,0 +1,18 @@
# ArrayHandle::Fill
`ArrayHandle` has a new method named `Fill`. As the name would suggest, the
`Fill` method initializes all elements in the array to a specified value.
In addition to being more convenient than calling `Algorithm::Fill` or
`ArrayCopy` with a constant array, the `ArrayHandle::Fill` can be used
without using a device adapter.
Calling `Fill` directly requires the `ArrayHandle` to first be allocated to
the appropriate size. The `ArrayHandle` now also has a new member named
`AllocateAndFill`. As the name would suggest, this method resizes the array
and then fills it with the specified value. Another feature this method has
over calling `Allocate` and `Fill` separately is if you call
`AllocateAndFill` with `vtkm::CopyFlag::On`, it will fill only the extended
portion of the array.
Also added a similar `Fill` and `AllocateAndFill` methods to `BitField` for
similar reasons.

@ -528,12 +528,81 @@ public:
}
///@}
///@{
/// \brief Allocates an array and fills it with an initial value.
///
/// `AllocateAndFill` behaves similar to `Allocate` except that after allocation it fills
/// the array with a given `fillValue`. This method is convenient when you wish to initialize
/// the array.
///
/// If the `preserve` flag is `vtkm::CopyFlag::On`, then any data that existed before the
/// call to `AllocateAndFill` will remain after the call (assuming the new array size is
/// large enough). If the array size is expanded, then the new values at the end will be
/// filled.
///
/// If the `preserve` flag is `vtkm::CopyFlag::Off` (the default), the entire array is
/// filled with the given `fillValue`.
///
VTKM_CONT void AllocateAndFill(vtkm::Id numberOfValues,
const ValueType& fillValue,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token) const
{
// Note that there is a slight potential for a race condition here. It is possible for someone
// else to resize the array in between getting the startIndex and locking the array in the
// Allocate call. If there really are 2 threads trying to allocate this array at the same time,
// you probably have bigger problems than filling at the wrong index.
vtkm::Id startIndex = (preserve == vtkm::CopyFlag::On) ? this->GetNumberOfValues() : 0;
this->Allocate(numberOfValues, preserve, token);
if (startIndex < numberOfValues)
{
this->Fill(fillValue, startIndex, numberOfValues, token);
}
}
VTKM_CONT void AllocateAndFill(vtkm::Id numberOfValues,
const ValueType& fillValue,
vtkm::CopyFlag preserve = vtkm::CopyFlag::Off) const
{
vtkm::cont::Token token;
this->AllocateAndFill(numberOfValues, fillValue, preserve, token);
}
///@}
VTKM_DEPRECATED(1.6, "Use Allocate(n, vtkm::CopyFlag::On) instead of Shrink(n).")
VTKM_CONT void Shrink(vtkm::Id numberOfValues)
{
this->Allocate(numberOfValues, vtkm::CopyFlag::On);
}
/// @{
/// \brief Fills the array with a given 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, 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, this->GetNumberOfValues(), token);
}
/// @}
/// Releases any resources being used in the execution environment (that are
/// not being shared by the control environment).
///

@ -52,6 +52,18 @@ public:
static_cast<vtkm::BufferSizeType>(sizeof(T)));
}
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, endIndex * fillValueSize, token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -110,6 +110,37 @@ public:
return numberOfBits;
}
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));
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, endBit / CHAR_BIT, token);
}
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, endBit / CHAR_BIT, token);
}
else
{
throw vtkm::cont::ErrorBadValue("Can only fill ArrayHandleBitField on 8-bit boundaries.");
}
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -248,6 +248,25 @@ public:
Storage3::GetNumberOfValues(Buffers3(buffers)));
}
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) || (endIndex != GetNumberOfValues(buffers)))
{
throw vtkm::cont::ErrorBadValue(
"Fill for ArrayHandleCartesianProduct can only be used to fill entire array.");
}
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,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -227,6 +227,8 @@ template <typename T, typename... StorageTags>
class Storage<vtkm::Vec<T, static_cast<vtkm::IdComponent>(sizeof...(StorageTags))>,
vtkm::cont::StorageTagCompositeVec<StorageTags...>>
{
using ValueType = vtkm::Vec<T, static_cast<vtkm::IdComponent>(sizeof...(StorageTags))>;
template <typename S>
using StorageFor = vtkm::cont::internal::Storage<T, S>;
@ -253,18 +255,6 @@ public:
typename StorageFor<StorageTags>::WritePortalType...>;
private:
// Hoop to jump through to use Storage::ResizeBuffer in an initializer list.
template <typename StorageType>
static bool ResizeBuffersCallthrough(StorageType,
vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
StorageType::ResizeBuffers(numValues, buffers, preserve, token);
return false; // Return value does not matter. Hopefully just thrown away by compiler.
}
template <std::size_t... Is>
static void ResizeBuffersImpl(vtkmstd::index_sequence<Is...>,
vtkm::Id numValues,
@ -272,11 +262,27 @@ private:
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
auto init_list = { ResizeBuffersCallthrough(vtkm::tuple_element_t<Is, StorageTuple>{},
numValues,
Buffers<Is>(buffers),
preserve,
token)... };
auto init_list = { (vtkm::tuple_element_t<Is, StorageTuple>::ResizeBuffers(
numValues, Buffers<Is>(buffers), preserve, token),
false)... };
(void)init_list;
}
template <std::size_t... Is>
static void FillImpl(vtkmstd::index_sequence<Is...>,
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,
endIndex,
token),
false)... };
(void)init_list;
}
@ -319,6 +325,15 @@ public:
ResizeBuffersImpl(IndexList{}, numValues, buffers, preserve, token);
}
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, endIndex, token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -202,6 +202,29 @@ public:
SourceStorage2::GetNumberOfValues(Buffers2(buffers)));
}
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) && (endIndex <= size1))
{
SourceStorage1::Fill(Buffers1(buffers), fillValue, startIndex, endIndex, token);
}
else if (startIndex < size1) // && (endIndex > size1)
{
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);
}
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -119,6 +119,15 @@ public:
return buffers[0].GetMetaData<DiscardMetaData>().NumberOfValues;
}
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer*,
const ValueType&,
vtkm::Id,
vtkm::Id,
vtkm::cont::Token&)
{
// Fill is a NO-OP.
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer*,
vtkm::cont::DeviceAdapterId,
vtkm::cont::Token&)

@ -129,6 +129,15 @@ public:
return SourceStorage::GetNumberOfValues(SourceBuffers(buffers));
}
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.");
}
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
vtkm::CopyFlag preserve,

@ -147,6 +147,15 @@ public:
return componentsSize / NUM_COMPONENTS;
}
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.");
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -158,6 +158,15 @@ public:
return OffsetsStorage::GetNumberOfValues(OffsetsBuffers(buffers)) - 1;
}
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.");
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -170,6 +170,20 @@ struct MultiplexerResizeBuffersFunctor
}
};
struct MultiplexerFillFunctor
{
template <typename ValueType, typename StorageType>
VTKM_CONT void operator()(StorageType,
vtkm::cont::internal::Buffer* buffers,
const ValueType& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token) const
{
StorageType::Fill(buffers, fillValue, startIndex, endIndex, token);
}
};
template <typename ReadPortalType>
struct MultiplexerCreateReadPortalFunctor
{
@ -256,6 +270,20 @@ public:
detail::MultiplexerResizeBuffersFunctor{}, numValues, ArrayBuffers(buffers), preserve, token);
}
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,
endIndex,
token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -65,10 +65,11 @@ class VTKM_ALWAYS_EXPORT
using OffsetsStorage = vtkm::cont::internal::Storage<vtkm::Id, OffsetsStorageTag>;
public:
VTKM_STORAGE_NO_RESIZE;
VTKM_STORAGE_NO_WRITE_PORTAL;
using ReadPortalType =
vtkm::internal::ArrayPortalOffsetsToNumComponents<typename OffsetsStorage::ReadPortalType>;
// Writing to ArrayHandleOffsetsToNumComponents not really supported, but we need to define this.
using WritePortalType = ReadPortalType;
VTKM_CONT static constexpr vtkm::IdComponent GetNumberOfBuffers()
{
@ -86,23 +87,6 @@ public:
return numOffsets - 1;
}
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
vtkm::CopyFlag,
vtkm::cont::Token&)
{
if (numValues == GetNumberOfValues(buffers))
{
// In general, we don't allow resizing of the array, but if it was "allocated" to the
// correct size, we will allow that.
}
else
{
throw vtkm::cont::ErrorBadAllocation(
"Cannot allocate/resize ArrayHandleOffsetsToNumComponents.");
}
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
@ -110,13 +94,6 @@ public:
VTKM_ASSERT(OffsetsStorage::GetNumberOfValues(buffers) > 0);
return ReadPortalType(OffsetsStorage::CreateReadPortal(buffers, device, token));
}
VTKM_CONT static WritePortalType CreateWritePortal(const vtkm::cont::internal::Buffer*,
vtkm::cont::DeviceAdapterId,
vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadAllocation("Cannot write to implicit arrays.");
}
};
} // namespace internal

@ -140,6 +140,15 @@ public:
return IndexStorage::GetNumberOfValues(IndexBuffers(buffers));
}
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.");
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -442,6 +442,15 @@ public:
return SourceStorage::GetNumberOfValues(BuffersForComponent(buffers, 0));
}
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.");
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -146,6 +146,16 @@ public:
return SourceStorage::GetNumberOfValues(buffers);
}
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 numValues = GetNumberOfValues(buffers);
SourceStorage::Fill(buffers, fillValue, numValues - endIndex, numValues - startIndex, token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -162,6 +162,23 @@ public:
static_cast<vtkm::Id>(sizeof(ComponentType));
}
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, endByte, token);
}
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -11,6 +11,7 @@
#define vtk_m_cont_ArrayHandleStride_h
#include <vtkm/cont/ArrayHandleBasic.h>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/internal/ArrayPortalBasic.h>
@ -174,6 +175,15 @@ public:
return GetInfo(buffers).NumberOfValues;
}
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.");
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -168,6 +168,20 @@ public:
return ReadPortalType(SourceStorage::CreateReadPortal(buffers + 1, device, token), indices);
}
VTKM_CONT static void Fill(vtkm::cont::internal::Buffer* buffers,
const T& fillValue,
vtkm::Id startIndex,
vtkm::Id endIndex,
vtkm::cont::Token& token)
{
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,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -181,6 +181,16 @@ public:
return numValues;
}
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, endIndex, token);
SecondStorage::Fill(SecondArrayBuffers(buffers), fillValue.second, startIndex, endIndex, token);
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)

@ -70,6 +70,13 @@ void BitField::Allocate(vtkm::Id numberOfBits,
this->Buffer.GetMetaData<internal::BitFieldMetaData>().NumberOfBits = numberOfBits;
}
void BitField::FillImpl(const void* word,
vtkm::BufferSizeType wordSize,
vtkm::cont::Token& token) const
{
this->Buffer.Fill(word, wordSize, 0, this->Buffer.GetNumberOfBytes(), token);
}
void BitField::ReleaseResourcesExecution()
{
this->Buffer.ReleaseDeviceResources();

@ -546,6 +546,8 @@ public:
using PortalConstControl VTKM_DEPRECATED(1.6, "Use ArrayBitField::ReadPortalType instead.") =
detail::BitPortalConst;
using WordTypePreferred = vtkm::AtomicTypePreferred;
template <typename Device>
struct ExecutionTypes
{
@ -622,6 +624,53 @@ public:
this->Allocate(numberOfBits, preserve, token);
}
/// Allocate the requested number of bits and fill with the requested bit or word.
template <typename ValueType>
VTKM_CONT void AllocateAndFill(vtkm::Id numberOfBits,
ValueType value,
vtkm::cont::Token& token) const
{
this->Allocate(numberOfBits, vtkm::CopyFlag::Off, token);
this->Fill(value, token);
}
template <typename ValueType>
VTKM_CONT void AllocateAndFill(vtkm::Id numberOfBits, ValueType value) const
{
vtkm::cont::Token token;
this->AllocateAndFill(numberOfBits, value, token);
}
private:
VTKM_CONT void FillImpl(const void* word,
vtkm::BufferSizeType wordSize,
vtkm::cont::Token& token) const;
public:
/// Set subsequent words to the given word of bits.
template <typename WordType>
VTKM_CONT void Fill(WordType word, vtkm::cont::Token& token) const
{
this->FillImpl(&word, static_cast<vtkm::BufferSizeType>(sizeof(WordType)), token);
}
template <typename WordType>
VTKM_CONT void Fill(WordType word) const
{
vtkm::cont::Token token;
this->Fill(word, token);
}
/// Set all the bits to the given value
VTKM_CONT void Fill(bool value, vtkm::cont::Token& token) const
{
using WordType = WordTypePreferred;
this->Fill(value ? ~WordType{ 0 } : WordType{ 0 }, token);
}
VTKM_CONT void Fill(bool value) const
{
vtkm::cont::Token token;
this->Fill(value, token);
}
/// Shrink the bit field to the requested number of bits.
VTKM_CONT VTKM_DEPRECATED(1.6,
"Use Allocate with preserve = On.") void Shrink(vtkm::Id numberOfBits)

@ -163,7 +163,6 @@ set(sources
ErrorBadType.cxx
FieldRangeCompute.cxx
FieldRangeGlobalCompute.cxx
internal/Buffer.cxx
internal/DeviceAdapterMemoryManager.cxx
internal/DeviceAdapterMemoryManagerShared.cxx
internal/RuntimeDeviceConfiguration.cxx
@ -193,6 +192,7 @@ set(device_sources
ColorTable.cxx
ConvertNumComponentsToOffsets.cxx
Field.cxx
internal/Buffer.cxx
MergePartitionedDataSet.cxx
PointLocatorSparseGrid.cxx
RuntimeDeviceInformation.cxx

@ -134,6 +134,14 @@ 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 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.
///
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
@ -181,6 +189,17 @@ struct StorageTraits<vtkm::cont::internal::Storage<T, S>>
#define VTKM_STORAGE_NO_WRITE_PORTAL \
using WritePortalType = vtkm::internal::ArrayPortalDummy< \
typename vtkm::cont::internal::StorageTraits<Storage>::ValueType>; \
VTKM_CONT static void Fill( \
vtkm::cont::internal::Buffer*, \
const typename vtkm::cont::internal::StorageTraits<Storage>::ValueType&, \
vtkm::Id, \
vtkm::Id, \
vtkm::cont::Token&) \
{ \
throw vtkm::cont::ErrorBadAllocation( \
"Cannot write to arrays with storage type of " + \
vtkm::cont::TypeToString<typename vtkm::cont::internal::StorageTraits<Storage>::Tag>()); \
} \
VTKM_CONT static WritePortalType CreateWritePortal( \
vtkm::cont::internal::Buffer*, vtkm::cont::DeviceAdapterId, vtkm::cont::Token&) \
{ \

@ -10,14 +10,18 @@
#include <vtkm/internal/Assume.h>
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/cont/ErrorBadAllocation.h>
#include <vtkm/cont/ErrorBadDevice.h>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/RuntimeDeviceInformation.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/cont/internal/Buffer.h>
#include <vtkm/cont/internal/DeviceAdapterMemoryManager.h>
#include <vtkm/exec/FunctorBase.h>
#include <condition_variable>
#include <cstring>
#include <deque>
@ -45,6 +49,12 @@ vtkm::BufferSizeType NumberOfValuesToNumberOfBytes(vtkm::Id numValues, std::size
} // namespace vtkm::internal
namespace
// nvcc whines about things like conversion operators that are defined but never used.
// I don't want to delete them because you never know when the code is going to change.
// So make the namespace technically not anonymous.
#ifdef VTKM_CUDA
vtkm_buffer_ns
#endif
{
using LockType = std::unique_lock<std::mutex>;
@ -157,7 +167,92 @@ struct MetaDataManager
}
};
template <typename T>
struct FillFunctor : vtkm::exec::FunctorBase
{
T* TargetArray;
const T* SourceValues;
vtkm::Id NumSourceValues;
VTKM_CONT FillFunctor(void* targetArray,
const void* sourceValues,
vtkm::BufferSizeType sourceValuesSize,
vtkm::BufferSizeType start)
: TargetArray(reinterpret_cast<T*>(targetArray))
, SourceValues(reinterpret_cast<const T*>(sourceValues))
, NumSourceValues(sourceValuesSize / sizeof(T))
{
VTKM_ASSERT((sourceValuesSize % sizeof(T)) == 0);
VTKM_ASSERT((start % sizeof(T)) == 0);
this->TargetArray += start / sizeof(T);
}
VTKM_EXEC void operator()(vtkm::Id index) const
{
T* target = this->TargetArray + (index * this->NumSourceValues);
for (vtkm::Id sourceIndex = 0; sourceIndex < this->NumSourceValues; ++sourceIndex)
{
*target = this->SourceValues[sourceIndex];
++target;
}
}
};
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)
{
void* targetPointer = target.WritePointerDevice(device, token);
const void* sourcePointer = source.ReadPointerDevice(device, token);
// Get after target locked with token.
vtkm::BufferSizeType targetSize = target.GetNumberOfBytes();
vtkm::BufferSizeType sourceSize = source.GetNumberOfBytes();
if (targetSize <= start)
{
return;
}
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 = (end - start) / sourceSize;
if ((sourceSize >= 8) && ((sourceSize % 8) == 0))
{
vtkm::cont::DeviceAdapterAlgorithm<Device>::Schedule(
FillFunctor<vtkm::UInt64>{ targetPointer, sourcePointer, sourceSize, start },
numSourceRepetitions);
}
else if ((sourceSize >= 4) && ((sourceSize % 4) == 0))
{
vtkm::cont::DeviceAdapterAlgorithm<Device>::Schedule(
FillFunctor<vtkm::UInt32>{ targetPointer, sourcePointer, sourceSize, start },
numSourceRepetitions);
}
else
{
vtkm::cont::DeviceAdapterAlgorithm<Device>::Schedule(
FillFunctor<vtkm::UInt8>{ targetPointer, sourcePointer, sourceSize, start },
numSourceRepetitions);
}
}
} // anonymous namespace
#ifdef VTKM_CUDA
using namespace vtkm_buffer_ns;
#endif
namespace vtkm
{
@ -1017,6 +1112,45 @@ vtkm::cont::internal::BufferInfo Buffer::GetDeviceBufferInfo(
throw vtkm::cont::ErrorBadDevice("Called Buffer::GetDeviceBufferInfo with invalid device");
}
}
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;
sourceBuffer.Reset(vtkm::cont::internal::BufferInfo(
vtkm::cont::DeviceAdapterTagUndefined{},
const_cast<void*>(source),
const_cast<void*>(source),
sourceSize,
[](void*) {},
[](void*&, void*&, vtkm::BufferSizeType, vtkm::BufferSizeType) {}));
// First, try setting on any device that already has the data.
bool success = vtkm::cont::TryExecute([&](auto device) {
if (this->IsAllocatedOnDevice(device))
{
FillBuffer(*this, sourceBuffer, start, end, device, token);
return true;
}
else
{
return false;
}
});
if (!success)
{
// Likely the data was not on any device. Fill on any device.
vtkm::cont::TryExecute([&](auto device) {
FillBuffer(*this, sourceBuffer, start, end, device, token);
return true;
});
}
}
}
}
} // namespace vtkm::cont::internal

@ -310,6 +310,21 @@ public:
VTKM_CONT vtkm::cont::internal::TransferredBuffer TakeDeviceBufferOwnership(
vtkm::cont::DeviceAdapterId device);
/// \brief Fill up the buffer with particular values.
///
/// 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` and `end`. Values before the `start` and
/// after the `end` are not affected.
///
/// 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
{
return (this->Internals == rhs.Internals);

@ -186,6 +186,29 @@ void DoTest()
VTKM_TEST_ASSERT(buffer.IsAllocatedOnHost());
VTKM_TEST_ASSERT(!buffer.IsAllocatedOnDevice(device));
std::cout << "Fill buffer" << std::endl;
{
constexpr vtkm::BufferSizeType fillValueSize = static_cast<vtkm::BufferSizeType>(sizeof(T));
vtkm::cont::Token token;
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 = 0; index < ARRAY_SIZE / 2; ++index)
{
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);
}
}
std::cout << "Reset with device data" << std::endl;
std::vector<T> v(ARRAY_SIZE);
void* devicePointer = v.data();

@ -59,7 +59,7 @@ class TestingArrayHandleMultiplexer
static void BasicSwitch()
{
std::cout << std::endl << "--- Basic switch" << std::endl;
std::cout << "\n--- Basic switch" << std::endl;
using ValueType = vtkm::FloatDefault;
@ -93,7 +93,7 @@ class TestingArrayHandleMultiplexer
// algorithm on CUDA. Most likely related to:
// https://github.com/thrust/thrust/issues/928
// https://github.com/thrust/thrust/issues/1044
std::cout << std::endl << "--- Reduce" << std::endl;
std::cout << "\n--- Reduce" << std::endl;
using ValueType = vtkm::Vec3f;
using MultiplexerType = vtkm::cont::ArrayHandleMultiplexer<
@ -127,10 +127,62 @@ class TestingArrayHandleMultiplexer
}
}
static void Fill()
{
std::cout << "\n--- Fill" << std::endl;
using ValueType = vtkm::Vec3f;
using MultiplexerType = vtkm::cont::ArrayHandleMultiplexer<
vtkm::cont::ArrayHandleConstant<ValueType>,
vtkm::cont::ArrayHandleCounting<ValueType>,
vtkm::cont::ArrayHandle<ValueType>,
vtkm::cont::ArrayHandleUniformPointCoordinates,
vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<vtkm::FloatDefault>>>;
const ValueType testValue1 = TestValue(1, ValueType{});
const ValueType testValue2 = TestValue(2, ValueType{});
MultiplexerType multiplexer = vtkm::cont::ArrayHandle<ValueType>{};
multiplexer.AllocateAndFill(ARRAY_SIZE, testValue1);
{
auto portal = multiplexer.ReadPortal();
VTKM_TEST_ASSERT(portal.GetNumberOfValues() == ARRAY_SIZE);
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
{
VTKM_TEST_ASSERT(portal.Get(index) == testValue1);
}
}
vtkm::cont::ArrayHandle<vtkm::FloatDefault> array1;
array1.Allocate(ARRAY_SIZE);
vtkm::cont::ArrayHandle<vtkm::FloatDefault> array2;
array2.Allocate(ARRAY_SIZE);
vtkm::cont::ArrayHandle<vtkm::FloatDefault> array3;
array3.Allocate(ARRAY_SIZE);
multiplexer = vtkm::cont::make_ArrayHandleCartesianProduct(array1, array2, array3);
multiplexer.Fill(testValue2);
{
auto portal1 = array1.ReadPortal();
auto portal2 = array2.ReadPortal();
auto portal3 = array3.ReadPortal();
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
{
VTKM_TEST_ASSERT(portal1.Get(index) == testValue2[0]);
VTKM_TEST_ASSERT(portal2.Get(index) == testValue2[1]);
VTKM_TEST_ASSERT(portal3.Get(index) == testValue2[2]);
}
}
}
static void TestAll()
{
BasicSwitch();
Reduce();
Fill();
}
public:

@ -700,6 +700,40 @@ private:
}
};
struct VerifyFill
{
template <typename T>
VTKM_CONT void operator()(T) const
{
std::cout << "Initialize values of array." << std::endl;
const T testValue1 = TestValue(13, T{});
vtkm::cont::ArrayHandle<T> array;
array.AllocateAndFill(ARRAY_SIZE, testValue1);
{
auto portal = array.ReadPortal();
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
{
VTKM_TEST_ASSERT(portal.Get(index) == testValue1);
}
}
std::cout << "Grow array with new values." << std::endl;
const T testValue2 = TestValue(42, T{});
array.AllocateAndFill(ARRAY_SIZE * 2, testValue2, vtkm::CopyFlag::On);
{
auto portal = array.ReadPortal();
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
{
VTKM_TEST_ASSERT(portal.Get(index) == testValue1);
}
for (vtkm::Id index = ARRAY_SIZE; index < ARRAY_SIZE * 2; ++index)
{
VTKM_TEST_ASSERT(portal.Get(index) == testValue2);
}
}
}
};
struct TryArrayHandleType
{
void operator()() const
@ -712,6 +746,7 @@ private:
vtkm::testing::Testing::TryTypes(VerifyVTKMAllocatedHandle{});
vtkm::testing::Testing::TryTypes(VerifyVTKMTransferredOwnership{});
vtkm::testing::Testing::TryTypes(VerifyEqualityOperators{});
vtkm::testing::Testing::TryTypes(VerifyFill{});
}
};

@ -531,6 +531,31 @@ struct TestingBitField
testMask64(129, 0x0000000000000001);
}
VTKM_CONT static void TestFill()
{
vtkm::cont::BitField bitField;
bitField.Allocate(NUM_BITS);
bitField.Fill(true);
{
auto portal = bitField.ReadPortal();
for (vtkm::Id index = 0; index < NUM_BITS; ++index)
{
VTKM_TEST_ASSERT(portal.GetBit(index));
}
}
constexpr vtkm::UInt8 word8 = 0xA6;
bitField.Fill(word8);
{
auto portal = bitField.ReadPortal();
for (vtkm::Id index = 0; index < NUM_BITS; ++index)
{
VTKM_TEST_ASSERT(portal.GetBit(index) == ((word8 >> (index % 8)) & 0x01));
}
}
}
struct ArrayHandleBitFieldChecker : vtkm::exec::FunctorBase
{
using PortalType = vtkm::cont::ArrayHandleBitField::WritePortalType;
@ -574,13 +599,34 @@ struct TestingBitField
" got: ",
numBits);
vtkm::cont::Token token;
Algo::Schedule(
ArrayHandleBitFieldChecker{ handle.PrepareForInPlace(DeviceAdapterTag{}, token), false },
numBits);
Algo::Schedule(
ArrayHandleBitFieldChecker{ handle.PrepareForInPlace(DeviceAdapterTag{}, token), true },
numBits);
{
vtkm::cont::Token token;
Algo::Schedule(
ArrayHandleBitFieldChecker{ handle.PrepareForInPlace(DeviceAdapterTag{}, token), false },
numBits);
Algo::Schedule(
ArrayHandleBitFieldChecker{ handle.PrepareForInPlace(DeviceAdapterTag{}, token), true },
numBits);
}
handle.Fill(true);
{
auto portal = handle.ReadPortal();
for (vtkm::Id index = 0; index < NUM_BITS; ++index)
{
VTKM_TEST_ASSERT(portal.Get(index));
}
}
handle.Fill(false, 24);
handle.Fill(true, 64);
{
auto portal = handle.ReadPortal();
for (vtkm::Id index = 0; index < NUM_BITS; ++index)
{
VTKM_TEST_ASSERT(portal.Get(index) == ((index < 24) || (index >= 64)));
}
}
}
VTKM_CONT
@ -647,6 +693,7 @@ struct TestingBitField
TestingBitField::TestControlPortals();
TestingBitField::TestExecutionPortals();
TestingBitField::TestFinalWordMask();
TestingBitField::TestFill();
TestingBitField::TestArrayHandleBitField();
TestingBitField::TestArrayInvokeWorklet();
TestingBitField::TestArrayInvokeWorklet2();

@ -1495,6 +1495,28 @@ private:
VTKM_TEST_ASSERT(test_equal(result_value, ValueType(static_cast<ValueComponentType>(i))),
"ArrayHandleZip Failed as input for value");
}
// Test filling the zipped array.
vtkm::cont::printSummary_ArrayHandle(result_zip, std::cout, true);
PairType fillValue{ TestValue(1, KeyType{}), TestValue(2, ValueType{}) };
result_zip.Fill(fillValue, 1);
vtkm::cont::printSummary_ArrayHandle(result_zip, std::cout, true);
keysPortal = result_keys.ReadPortal();
valsPortal = result_values.ReadPortal();
// First entry should be the same.
VTKM_TEST_ASSERT(
test_equal(keysPortal.Get(0), KeyType(static_cast<KeyComponentType>(ARRAY_SIZE))));
VTKM_TEST_ASSERT(
test_equal(valsPortal.Get(0), ValueType(static_cast<ValueComponentType>(0))));
// The rest should be fillValue
for (vtkm::Id index = 1; index < ARRAY_SIZE; ++index)
{
const KeyType result_key = keysPortal.Get(index);
const ValueType result_value = valsPortal.Get(index);
VTKM_TEST_ASSERT(test_equal(result_key, fillValue.first));
VTKM_TEST_ASSERT(test_equal(result_value, fillValue.second));
}
}
};

@ -219,6 +219,36 @@ void TryVector()
TryVector1(MakeInputArray<vtkm::Vec3f>(0));
}
void TryFill()
{
std::cout << "Trying fill." << std::endl;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> array0;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> array1;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> array2;
auto composite = vtkm::cont::make_ArrayHandleCompositeVector(array0, array1, array2);
const vtkm::Vec3f testValue = TestValue(0, vtkm::Vec3f{});
composite.AllocateAndFill(ARRAY_SIZE, testValue);
auto portal0 = array0.ReadPortal();
auto portal1 = array1.ReadPortal();
auto portal2 = array2.ReadPortal();
VTKM_TEST_ASSERT(portal0.GetNumberOfValues() == ARRAY_SIZE);
VTKM_TEST_ASSERT(portal1.GetNumberOfValues() == ARRAY_SIZE);
VTKM_TEST_ASSERT(portal2.GetNumberOfValues() == ARRAY_SIZE);
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
{
VTKM_TEST_ASSERT(portal0.Get(index) == testValue[0]);
VTKM_TEST_ASSERT(portal1.Get(index) == testValue[1]);
VTKM_TEST_ASSERT(portal2.Get(index) == testValue[2]);
}
}
void TrySpecialArrays()
{
std::cout << "Trying special arrays." << std::endl;
@ -251,6 +281,8 @@ void TestCompositeVector()
TryVector();
TryFill();
TrySpecialArrays();
}

@ -13,12 +13,12 @@
#include <vtkm/cont/testing/Testing.h>
namespace UnitTestArrayHandleConcatenateNamespace
namespace
{
const vtkm::Id ARRAY_SIZE = 5;
constexpr vtkm::Id ARRAY_SIZE = 4;
void TestArrayHandleConcatenate()
void TestConcatOfConcat()
{
vtkm::cont::ArrayHandleIndex array1(ARRAY_SIZE);
vtkm::cont::ArrayHandleIndex array2(2 * ARRAY_SIZE);
@ -36,10 +36,21 @@ void TestArrayHandleConcatenate()
array5 = vtkm::cont::make_ArrayHandleConcatenate(array3, array4);
}
auto array5Portal = array5.ReadPortal();
for (vtkm::Id index = 0; index < array5.GetNumberOfValues(); index++)
vtkm::cont::printSummary_ArrayHandle(array5, std::cout, true);
VTKM_TEST_ASSERT(array5.GetNumberOfValues() == 4 * ARRAY_SIZE);
// Check the values in array5. If array5 is correct, all the `ArrayHandleConcatinate`s
// (such as in array3) must be working.
auto portal = array5.ReadPortal();
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
{
std::cout << array5Portal.Get(index) << std::endl;
VTKM_TEST_ASSERT(portal.Get(index) == index);
VTKM_TEST_ASSERT(portal.Get(index + (3 * ARRAY_SIZE)) == index);
}
for (vtkm::Id index = 0; index < (2 * ARRAY_SIZE); ++index)
{
VTKM_TEST_ASSERT(portal.Get(index + ARRAY_SIZE) == index);
}
}
@ -47,7 +58,9 @@ void TestConcatenateEmptyArray()
{
std::vector<vtkm::Float64> vec;
for (vtkm::Id i = 0; i < ARRAY_SIZE; i++)
{
vec.push_back(vtkm::Float64(i) * 1.5);
}
using CoeffValueType = vtkm::Float64;
using CoeffArrayTypeTmp = vtkm::cont::ArrayHandle<CoeffValueType>;
@ -60,16 +73,59 @@ void TestConcatenateEmptyArray()
ArrayConcat arrConc(arr2, arr1);
ArrayConcat2 arrConc2(arrConc, arr3);
auto arrConc2Portal = arrConc2.ReadPortal();
for (vtkm::Id i = 0; i < arrConc2.GetNumberOfValues(); i++)
std::cout << arrConc2Portal.Get(i) << std::endl;
vtkm::cont::printSummary_ArrayHandle(arrConc2, std::cout, true);
VTKM_TEST_ASSERT(arrConc2.GetNumberOfValues() == ARRAY_SIZE);
}
} // namespace UnitTestArrayHandleIndexNamespace
void TestConcatenateFill()
{
using T = vtkm::FloatDefault;
vtkm::cont::ArrayHandle<T> array1;
vtkm::cont::ArrayHandle<T> array2;
array1.Allocate(ARRAY_SIZE);
array2.Allocate(ARRAY_SIZE);
auto concatArray = vtkm::cont::make_ArrayHandleConcatenate(array1, array2);
const T value0 = TestValue(0, T{});
const T value1 = TestValue(1, T{});
const T value2 = TestValue(2, T{});
VTKM_STATIC_ASSERT_MSG((ARRAY_SIZE % 2) == 0, "ARRAY_SIZE must be even for this test.");
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);
auto portal = concatArray.ReadPortal();
for (vtkm::Id index = 0; index < (ARRAY_SIZE / 2); ++index)
{
VTKM_TEST_ASSERT(portal.Get(index) == value0);
}
for (vtkm::Id index = (ARRAY_SIZE / 2); index < (3 * ARRAY_SIZE / 2); ++index)
{
VTKM_TEST_ASSERT(portal.Get(index) == value1);
}
for (vtkm::Id index = (3 * ARRAY_SIZE / 2); index < (2 * ARRAY_SIZE); ++index)
{
VTKM_TEST_ASSERT(portal.Get(index) == value2);
}
}
void TestArrayHandleConcatenate()
{
TestConcatOfConcat();
TestConcatenateEmptyArray();
TestConcatenateFill();
}
} // anonymous namespace
int UnitTestArrayHandleConcatenate(int argc, char* argv[])
{
using namespace UnitTestArrayHandleConcatenateNamespace;
//TestConcatenateEmptyArray();
return vtkm::cont::testing::Testing::Run(TestArrayHandleConcatenate, argc, argv);
}

@ -278,7 +278,7 @@ struct DecoratorTests
auto ah1 = vtkm::cont::make_ArrayHandleCounting(ValueType{ 0 }, ValueType{ 2 }, ARRAY_SIZE);
auto ah2 = vtkm::cont::make_ArrayHandleConstant(ValueType{ ARRAY_SIZE }, ARRAY_SIZE);
vtkm::cont::ArrayHandle<ValueType> ah3;
vtkm::cont::Algorithm::Fill(ah3, ValueType{ ARRAY_SIZE / 2 }, ARRAY_SIZE);
ah3.AllocateAndFill(ARRAY_SIZE, ValueType{ ARRAY_SIZE / 2 });
auto ah3Const = vtkm::cont::make_ArrayHandleConstant(ValueType{ ARRAY_SIZE / 2 }, ARRAY_SIZE);

@ -107,10 +107,18 @@ struct Test
handle.PrepareForOutput(ARRAY_SIZE, DeviceTag(), token);
}
void TestFill()
{
DiscardHandle array;
array.AllocateAndFill(ARRAY_SIZE, ValueType{ 0 });
VTKM_TEST_ASSERT(array.GetNumberOfValues() == ARRAY_SIZE);
}
void operator()()
{
TestReduceByKey();
TestPrepareExceptions();
TestFill();
}
};

@ -88,11 +88,26 @@ void TestArrayHandleReverseScanInclusiveByKey()
std::cout << std::endl;
}
void TestArrayHandleReverseFill()
{
vtkm::cont::ArrayHandle<vtkm::Id> handle;
auto reverse = vtkm::cont::make_ArrayHandleReverse(handle);
reverse.AllocateAndFill(ARRAY_SIZE, 20, vtkm::CopyFlag::Off);
VTKM_TEST_ASSERT(reverse.GetNumberOfValues() == ARRAY_SIZE);
auto portal = reverse.ReadPortal();
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
{
VTKM_TEST_ASSERT(portal.Get(index) == 20);
}
}
void TestArrayHandleReverse()
{
TestArrayHandleReverseRead();
TestArrayHandleReverseWrite();
TestArrayHandleReverseScanInclusiveByKey();
TestArrayHandleReverseFill();
}
}; // namespace UnitTestArrayHandleReverseNamespace

@ -348,16 +348,16 @@ public:
auto activePoints = vtkm::cont::make_ArrayHandleBitField(activePointBits);
vtkm::cont::BitField activeCellBits;
vtkm::cont::Algorithm::Fill(activeCellBits, false, numCells);
activeCellBits.AllocateAndFill(numCells, false);
auto activeCells = vtkm::cont::make_ArrayHandleBitField(activeCellBits);
// visited = cells / points that have been corrected.
vtkm::cont::BitField visitedPointBits;
vtkm::cont::Algorithm::Fill(visitedPointBits, false, numPoints);
visitedPointBits.AllocateAndFill(numPoints, false);
auto visitedPoints = vtkm::cont::make_ArrayHandleBitField(visitedPointBits);
vtkm::cont::BitField visitedCellBits;
vtkm::cont::Algorithm::Fill(visitedCellBits, false, numCells);
visitedCellBits.AllocateAndFill(numCells, false);
auto visitedCells = vtkm::cont::make_ArrayHandleBitField(visitedCellBits);
vtkm::cont::Invoker invoke;

@ -330,7 +330,7 @@ public:
auto activePoints = vtkm::cont::make_ArrayHandleBitField(activePointBits);
vtkm::cont::BitField activeCellBits;
vtkm::cont::Algorithm::Fill(activeCellBits, false, numCells);
activeCellBits.AllocateAndFill(numCells, false);
auto activeCells = vtkm::cont::make_ArrayHandleBitField(activeCellBits);
// visited = cells / points that have been corrected.
@ -338,7 +338,7 @@ public:
auto visitedPoints = vtkm::cont::make_ArrayHandleBitField(visitedPointBits);
vtkm::cont::BitField visitedCellBits;
vtkm::cont::Algorithm::Fill(visitedCellBits, false, numCells);
visitedCellBits.AllocateAndFill(numCells, false);
auto visitedCells = vtkm::cont::make_ArrayHandleBitField(visitedCellBits);
vtkm::cont::ArrayHandle<vtkm::Id> mask; // Allocated as needed

@ -291,7 +291,7 @@ public:
auto activePoints = vtkm::cont::make_ArrayHandleBitField(activePointBits);
vtkm::cont::BitField activeCellBits;
vtkm::cont::Algorithm::Fill(activeCellBits, false, numCells);
activeCellBits.AllocateAndFill(numCells, false);
auto activeCells = vtkm::cont::make_ArrayHandleBitField(activeCellBits);
// visited = cells / points that have been corrected.
@ -299,7 +299,7 @@ public:
auto visitedPoints = vtkm::cont::make_ArrayHandleBitField(visitedPointBits);
vtkm::cont::BitField visitedCellBits;
vtkm::cont::Algorithm::Fill(visitedCellBits, false, numCells);
visitedCellBits.AllocateAndFill(numCells, false);
auto visitedCells = vtkm::cont::make_ArrayHandleBitField(visitedCellBits);
vtkm::cont::ArrayHandle<vtkm::Id> mask; // Allocated as needed

@ -173,7 +173,7 @@ struct launchComputePass1
vtkm::cont::Invoker invoke(device);
metaDataMesh2D = make_metaDataMesh2D(SumYAxis{}, worklet.PointDims);
vtkm::cont::Algorithm::Fill(edgeCases, static_cast<vtkm::UInt8>(FlyingEdges3D::Below));
edgeCases.Fill(static_cast<vtkm::UInt8>(FlyingEdges3D::Below));
invoke(worklet, metaDataMesh2D, std::forward<Args>(args)..., edgeCases, inputField);
return true;
}

@ -738,9 +738,8 @@ inline void ContourTreeMesh<FieldType>::MergeWith(ContourTreeMesh<FieldType>& ot
vtkm::cont::ArrayHandle<vtkm::IdComponent> thisToCombinedSortOrderIsDuplicate;
thisToCombinedSortOrderIsDuplicate.Allocate(thisToCombinedSortOrder.GetNumberOfValues());
vtkm::cont::ArrayHandle<vtkm::IdComponent> otherToCombinedSortOrderIsDuplicate;
vtkm::cont::Algorithm::Fill(otherToCombinedSortOrderIsDuplicate,
vtkm::IdComponent{ 0 },
otherToCombinedSortOrder.GetNumberOfValues());
otherToCombinedSortOrderIsDuplicate.AllocateAndFill(otherToCombinedSortOrder.GetNumberOfValues(),
vtkm::IdComponent{ 0 });
this->Invoke(contourtree_mesh_inc_ns::FindDuplicateInOtherWorklet{},
thisToCombinedSortOrder,
otherToCombinedSortOrder,

@ -215,13 +215,10 @@ HierarchicalHyperSweeper<SweepValueType, ContourTreeFieldType>::HierarchicalHype
, NumOwnedRegularVertices(vtkm::Id{ 0 })
{ // constructor
// Initalize arrays with 0s
vtkm::cont::Algorithm::Fill(
this->ValuePrefixSum, vtkm::Id{ 0 }, this->HierarchicalTree.Supernodes.GetNumberOfValues());
vtkm::cont::Algorithm::Fill(
this->TransferTarget, vtkm::Id{ 0 }, this->HierarchicalTree.Supernodes.GetNumberOfValues());
vtkm::cont::Algorithm::Fill(this->SortedTransferTarget,
vtkm::Id{ 0 },
this->HierarchicalTree.Supernodes.GetNumberOfValues());
this->ValuePrefixSum.AllocateAndFill(this->HierarchicalTree.Supernodes.GetNumberOfValues(), 0);
this->TransferTarget.AllocateAndFill(this->HierarchicalTree.Supernodes.GetNumberOfValues(), 0);
this->SortedTransferTarget.AllocateAndFill(this->HierarchicalTree.Supernodes.GetNumberOfValues(),
0);
// Initialize the supersortPermute to the identity
vtkm::cont::ArrayHandleIndex tempIndexArray(
this->HierarchicalTree.Supernodes.GetNumberOfValues());
@ -295,8 +292,7 @@ void HierarchicalHyperSweeper<SweepValueType, ContourTreeFieldType>::InitializeI
#endif
// initialize the counts to zero.
vtkm::cont::Algorithm::Fill(
superarcRegularCounts, vtkm::Id{ 0 }, this->HierarchicalTree.Supernodes.GetNumberOfValues());
superarcRegularCounts.AllocateAndFill(this->HierarchicalTree.Supernodes.GetNumberOfValues(), 0);
// set the count to the Id one off the high end of each range
Invoke(vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper::

@ -222,8 +222,8 @@ private:
void Prepare()
{
vtkm::cont::Algorithm::Fill(this->VisitedPointsField, false, this->Coords.GetNumberOfPoints());
vtkm::cont::Algorithm::Fill(this->VisitedCellsField, false, this->Cells.GetNumberOfCells());
this->VisitedPointsField.AllocateAndFill(this->Coords.GetNumberOfPoints(), false);
this->VisitedCellsField.AllocateAndFill(this->Cells.GetNumberOfCells(), false);
}
void ValidateImpl(vtkm::Id startPtIdx, const NormalType& startRefNormal)

@ -44,7 +44,7 @@ vtkm::cont::DataSet GenerateDataSet()
const auto numCells = ds.GetNumberOfCells();
vtkm::cont::ArrayHandle<MyNormalT> cellNormals;
vtkm::cont::Algorithm::Fill(cellNormals, MyNormalT{ 1., 0., 0. }, numCells);
cellNormals.AllocateAndFill(numCells, MyNormalT{ 1., 0., 0. });
ds.AddField(vtkm::cont::make_FieldCell("normals", cellNormals));
return ds;