Make Storage class completely stateless

The old style `ArrayHandle` stored most of its state, including the
data, in the `vtkm::cont::internal::Storage` object (templated to the
type of array). The new style of `ArrayHandle` stores the data itself in
`Buffer` objects, and recent changes to `Buffer` allow metadata to be
stored there, too.

These changes make it pretty unnecessary to hold any state at all in the
`Storage` object. This is good since the sharing of state from one type
of `ArrayHandle` to another (such as by transforming the data), can be
done by just sharing the `Buffer` objects.

To reinforce this behavior, the `Storage` object has been changed to
make it completely stateless. All the methods of `Storage` must be
marked as `static`.
This commit is contained in:
Kenneth Moreland 2020-08-25 09:36:07 -06:00
parent c907ce6419
commit 0cc0f3f961
4 changed files with 147 additions and 167 deletions

@ -905,74 +905,75 @@ VTKM_CONT_EXPORT VTKM_CONT vtkm::cont::DeviceAdapterId ArrayHandleGetDeviceAdapt
//
// Don't forget to use VTKM_PASS_COMMAS if one of the macro arguments contains
// a template with multiple parameters.
#define VTKM_ARRAY_HANDLE_NEW_STYLE(ValueType_, StorageType_) \
class VTKM_ALWAYS_EXPORT ArrayHandle<ValueType_, StorageType_> \
: public ArrayHandleNewStyle<ValueType_, StorageType_> \
{ \
using Superclass = ArrayHandleNewStyle<ValueType_, StorageType_>; \
\
public: \
VTKM_CONT \
ArrayHandle() \
: Superclass() \
{ \
} \
\
VTKM_CONT \
ArrayHandle(const ArrayHandle<ValueType_, StorageType_>& src) \
: Superclass(src) \
{ \
} \
\
VTKM_CONT \
ArrayHandle(ArrayHandle<ValueType_, StorageType_>&& src) noexcept \
: Superclass(std::move(src)) \
{ \
} \
\
VTKM_CONT \
ArrayHandle(const ArrayHandleNewStyle<ValueType_, StorageType_>& src) \
: Superclass(src) \
{ \
} \
\
VTKM_CONT \
ArrayHandle(ArrayHandleNewStyle<ValueType_, StorageType_>&& src) noexcept \
: Superclass(std::move(src)) \
{ \
} \
\
VTKM_CONT ArrayHandle( \
const vtkm::cont::internal::Buffer* buffers, \
const typename Superclass::StorageType& storage = typename Superclass::StorageType()) \
: Superclass(buffers, storage) \
{ \
} \
\
VTKM_CONT ArrayHandle( \
const std::vector<vtkm::cont::internal::Buffer>& buffers, \
const typename Superclass::StorageType& storage = typename Superclass::StorageType()) \
: Superclass(buffers, storage) \
{ \
} \
\
VTKM_CONT \
ArrayHandle<ValueType_, StorageType_>& operator=( \
const ArrayHandle<ValueType_, StorageType_>& src) \
{ \
this->Superclass::operator=(src); \
return *this; \
} \
\
VTKM_CONT \
ArrayHandle<ValueType_, StorageType_>& operator=( \
ArrayHandle<ValueType_, StorageType_>&& src) noexcept \
{ \
this->Superclass::operator=(std::move(src)); \
return *this; \
} \
\
VTKM_CONT ~ArrayHandle() {} \
#define VTKM_ARRAY_HANDLE_NEW_STYLE(ValueType_, StorageType_) \
class VTKM_ALWAYS_EXPORT ArrayHandle<ValueType_, StorageType_> \
: public ArrayHandleNewStyle<ValueType_, StorageType_> \
{ \
using Superclass = ArrayHandleNewStyle<ValueType_, StorageType_>; \
\
public: \
VTKM_CONT \
ArrayHandle() \
: Superclass() \
{ \
} \
\
VTKM_CONT \
ArrayHandle(const ArrayHandle<ValueType_, StorageType_>& src) \
: Superclass(src) \
{ \
} \
\
VTKM_CONT \
ArrayHandle(ArrayHandle<ValueType_, StorageType_>&& src) noexcept \
: Superclass(std::move(src)) \
{ \
} \
\
VTKM_CONT \
ArrayHandle(const ArrayHandleNewStyle<ValueType_, StorageType_>& src) \
: Superclass(src) \
{ \
} \
\
VTKM_CONT \
ArrayHandle(ArrayHandleNewStyle<ValueType_, StorageType_>&& src) noexcept \
: Superclass(std::move(src)) \
{ \
} \
\
VTKM_CONT ArrayHandle(const vtkm::cont::internal::Buffer* buffers) \
: Superclass(buffers) \
{ \
} \
\
VTKM_CONT ArrayHandle(const std::vector<vtkm::cont::internal::Buffer>& buffers) \
: Superclass(buffers) \
{ \
} \
\
VTKM_CONT ArrayHandle(std::vector<vtkm::cont::internal::Buffer>&& buffers) \
: Superclass(std::move(buffers)) \
{ \
} \
\
VTKM_CONT \
ArrayHandle<ValueType_, StorageType_>& operator=( \
const ArrayHandle<ValueType_, StorageType_>& src) \
{ \
this->Superclass::operator=(src); \
return *this; \
} \
\
VTKM_CONT \
ArrayHandle<ValueType_, StorageType_>& operator=( \
ArrayHandle<ValueType_, StorageType_>&& src) noexcept \
{ \
this->Superclass::operator=(std::move(src)); \
return *this; \
} \
\
VTKM_CONT ~ArrayHandle() {} \
}
/// This new style of ArrayHandle will eventually replace the classic ArrayHandle
@ -1003,7 +1004,7 @@ public:
/// Constructs an empty ArrayHandle.
///
VTKM_CONT ArrayHandleNewStyle()
: Internals(std::make_shared<InternalsStruct>())
: Buffers(static_cast<std::size_t>(StorageType::GetNumberOfBuffers()))
{
}
@ -1015,7 +1016,7 @@ public:
/// created for all devices, and it would not be valid for all devices.
///
VTKM_CONT ArrayHandleNewStyle(const vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& src)
: Internals(src.Internals)
: Buffers(src.Buffers)
{
}
@ -1028,7 +1029,7 @@ public:
///
VTKM_CONT ArrayHandleNewStyle(
vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>&& src) noexcept
: Internals(std::move(src.Internals))
: Buffers(std::move(src.Buffers))
{
}
@ -1036,17 +1037,20 @@ public:
/// Special constructor for subclass specializations that need to set the
/// initial state array. Used when pulling data from other sources.
///
VTKM_CONT ArrayHandleNewStyle(const std::vector<vtkm::cont::internal::Buffer>& buffers,
const StorageType& storage = StorageType())
: Internals(std::make_shared<InternalsStruct>(buffers.data(), storage))
VTKM_CONT ArrayHandleNewStyle(const std::vector<vtkm::cont::internal::Buffer>& buffers)
: Buffers(buffers)
{
VTKM_ASSERT(static_cast<vtkm::IdComponent>(this->Internals->Buffers.size()) ==
this->GetNumberOfBuffers());
VTKM_ASSERT(static_cast<vtkm::IdComponent>(this->Buffers.size()) == this->GetNumberOfBuffers());
}
VTKM_CONT ArrayHandleNewStyle(const vtkm::cont::internal::Buffer* buffers,
const StorageType& storage = StorageType())
: Internals(std::make_shared<InternalsStruct>(buffers, storage))
VTKM_CONT ArrayHandleNewStyle(std::vector<vtkm::cont::internal::Buffer>&& buffers) noexcept
: Buffers(std::move(buffers))
{
VTKM_ASSERT(static_cast<vtkm::IdComponent>(this->Buffers.size()) == this->GetNumberOfBuffers());
}
VTKM_CONT ArrayHandleNewStyle(const vtkm::cont::internal::Buffer* buffers)
: Buffers(buffers, buffers + StorageType::GetNumberOfBuffers())
{
}
///@}
@ -1066,7 +1070,7 @@ public:
vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& operator=(
const vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& src)
{
this->Internals = src.Internals;
this->Buffers = src.Buffers;
return *this;
}
@ -1076,7 +1080,7 @@ public:
vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& operator=(
vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>&& src) noexcept
{
this->Internals = std::move(src.Internals);
this->Buffers = std::move(src.Buffers);
return *this;
}
@ -1086,13 +1090,13 @@ public:
VTKM_CONT
bool operator==(const ArrayHandle<ValueType, StorageTag>& rhs) const
{
return this->Internals == rhs.Internals;
return this->Buffers == rhs.Buffers;
}
VTKM_CONT
bool operator!=(const ArrayHandle<ValueType, StorageTag>& rhs) const
{
return this->Internals != rhs.Internals;
return this->Buffers != rhs.Buffers;
}
template <typename VT, typename ST>
@ -1109,12 +1113,12 @@ public:
VTKM_CONT vtkm::IdComponent GetNumberOfBuffers() const
{
return this->Internals->Storage.GetNumberOfBuffers();
return StorageType::GetNumberOfBuffers();
}
/// Get the storage.
///
VTKM_CONT const StorageType& GetStorage() const { return this->Internals->Storage; }
VTKM_CONT StorageType GetStorage() const { return StorageType{}; }
/// Get the array portal of the control array.
/// Since worklet invocations are asynchronous and this routine is a synchronization point,
@ -1158,7 +1162,7 @@ public:
VTKM_CONT ReadPortalType ReadPortal() const
{
vtkm::cont::Token token;
return this->Internals->Storage.CreateReadPortal(
return StorageType::CreateReadPortal(
this->GetBuffers(), vtkm::cont::DeviceAdapterTagUndefined{}, token);
}
@ -1175,7 +1179,7 @@ public:
{
vtkm::cont::Token token;
return this->Internals->Storage.CreateWritePortal(
return StorageType::CreateWritePortal(
this->GetBuffers(), vtkm::cont::DeviceAdapterTagUndefined{}, token);
}
@ -1183,7 +1187,7 @@ public:
///
VTKM_CONT vtkm::Id GetNumberOfValues() const
{
return this->Internals->Storage.GetNumberOfValues(this->GetBuffers());
return StorageType::GetNumberOfValues(this->GetBuffers());
}
///@{
@ -1202,7 +1206,7 @@ public:
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
this->Internals->Storage.ResizeBuffers(numberOfValues, this->GetBuffers(), preserve, token);
StorageType::ResizeBuffers(numberOfValues, this->GetBuffers(), preserve, token);
}
VTKM_CONT void Allocate(vtkm::Id numberOfValues, vtkm::CopyFlag preserve = vtkm::CopyFlag::Off)
@ -1223,7 +1227,7 @@ public:
///
VTKM_CONT void ReleaseResourcesExecution()
{
detail::ArrayHandleReleaseResourcesExecution(this->Internals->Buffers);
detail::ArrayHandleReleaseResourcesExecution(this->Buffers);
}
/// Releases all resources in both the control and execution environments.
@ -1246,7 +1250,7 @@ public:
VTKM_CONT ReadPortalType PrepareForInput(vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token) const
{
return this->Internals->Storage.CreateReadPortal(this->GetBuffers(), device, token);
return StorageType::CreateReadPortal(this->GetBuffers(), device, token);
}
/// Prepares this array to be used in an in-place operation (both as input
@ -1265,7 +1269,7 @@ public:
VTKM_CONT WritePortalType PrepareForInPlace(vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token) const
{
return this->Internals->Storage.CreateWritePortal(this->GetBuffers(), device, token);
return StorageType::CreateWritePortal(this->GetBuffers(), device, token);
}
/// Prepares (allocates) this array to be used as an output from an operation
@ -1287,7 +1291,7 @@ public:
vtkm::cont::Token& token)
{
this->Allocate(numberOfValues, vtkm::CopyFlag::Off, token);
return this->Internals->Storage.CreateWritePortal(this->GetBuffers(), device, token);
return StorageType::CreateWritePortal(this->GetBuffers(), device, token);
}
template <typename DeviceAdapterTag>
@ -1318,7 +1322,7 @@ public:
///
VTKM_CONT bool IsOnDevice(vtkm::cont::DeviceAdapterId device) const
{
return detail::ArrayHandleIsOnDevice(this->Internals->Buffers, device);
return detail::ArrayHandleIsOnDevice(this->Buffers, device);
}
/// Returns true if the ArrayHandle's data is on the host. If the data are on the given
@ -1341,7 +1345,7 @@ public:
VTKM_CONT
DeviceAdapterId GetDeviceAdapterId() const
{
return detail::ArrayHandleGetDeviceAdapterId(this->Internals->Buffers);
return detail::ArrayHandleGetDeviceAdapterId(this->Buffers);
}
/// Synchronizes the control array with the execution array. If either the
@ -1379,7 +1383,7 @@ public:
///
VTKM_CONT void Enqueue(const vtkm::cont::Token& token) const
{
for (auto&& buffer : this->Internals->Buffers)
for (auto&& buffer : this->Buffers)
{
buffer.Enqueue(token);
}
@ -1394,49 +1398,27 @@ public:
{
std::vector<vtkm::cont::internal::Buffer> destBuffers;
destBuffers.reserve(static_cast<std::size_t>(this->GetNumberOfBuffers()));
for (auto&& srcBuffer : this->Internals->Buffers)
for (auto&& srcBuffer : this->Buffers)
{
vtkm::cont::internal::Buffer destBuffer;
srcBuffer.DeepCopy(destBuffer);
destBuffers.push_back(std::move(destBuffer));
}
return vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>(destBuffers, this->GetStorage());
return vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>(destBuffers);
}
/// Returns the internal `Buffer` structures that hold the data.
///
VTKM_CONT vtkm::cont::internal::Buffer* GetBuffers() const
{
return this->Internals->Buffers.data();
}
VTKM_CONT vtkm::cont::internal::Buffer* GetBuffers() const { return this->Buffers.data(); }
private:
struct InternalsStruct
{
mutable std::vector<vtkm::cont::internal::Buffer> Buffers;
mutable StorageType Storage;
VTKM_CONT InternalsStruct(StorageType storage = StorageType())
: Buffers(static_cast<std::size_t>(storage.GetNumberOfBuffers()))
, Storage(storage)
{
}
VTKM_CONT InternalsStruct(const vtkm::cont::internal::Buffer* buffers,
const StorageType& storage)
: Buffers(static_cast<std::size_t>(storage.GetNumberOfBuffers()))
, Storage(storage)
{
std::copy(buffers, buffers + storage.GetNumberOfBuffers(), this->Buffers.begin());
}
};
std::shared_ptr<InternalsStruct> Internals;
mutable std::vector<vtkm::cont::internal::Buffer> Buffers;
protected:
VTKM_CONT void SetBuffer(vtkm::IdComponent index, const vtkm::cont::internal::Buffer& buffer)
{
this->Internals->Buffers[static_cast<std::size_t>(index)] = buffer;
this->Buffers[static_cast<std::size_t>(index)] = buffer;
}
// BufferContainer must be an iteratable container of Buffer objects.

@ -34,36 +34,36 @@ public:
using ReadPortalType = vtkm::internal::ArrayPortalBasicRead<T>;
using WritePortalType = vtkm::internal::ArrayPortalBasicWrite<T>;
VTKM_CONT vtkm::IdComponent GetNumberOfBuffers() const { return 1; }
VTKM_CONT static vtkm::IdComponent GetNumberOfBuffers() { return 1; }
VTKM_CONT void ResizeBuffers(vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
buffers[0].SetNumberOfBytes(
vtkm::internal::NumberOfValuesToNumberOfBytes<T>(numValues), preserve, token);
}
VTKM_CONT vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
{
return static_cast<vtkm::Id>(buffers->GetNumberOfBytes()) / static_cast<vtkm::Id>(sizeof(T));
}
VTKM_CONT ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return ReadPortalType(reinterpret_cast<const T*>(buffers[0].ReadPointerDevice(device, token)),
this->GetNumberOfValues(buffers));
GetNumberOfValues(buffers));
}
VTKM_CONT WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return WritePortalType(reinterpret_cast<T*>(buffers[0].WritePointerDevice(device, token)),
this->GetNumberOfValues(buffers));
GetNumberOfValues(buffers));
}
};

@ -82,14 +82,12 @@ public:
using ReadPortalType = vtkm::cont::internal::ArrayPortalBitField<BitPortalConstType>;
using WritePortalType = vtkm::cont::internal::ArrayPortalBitField<BitPortalType>;
VTKM_CONT vtkm::IdComponent GetNumberOfBuffers() const { return 1; }
VTKM_CONT static vtkm::IdComponent GetNumberOfBuffers() { return 1; }
VTKM_CONT Storage() {}
VTKM_CONT void ResizeBuffers(vtkm::Id numberOfBits,
vtkm::cont::internal::Buffer* buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
VTKM_CONT static void ResizeBuffers(vtkm::Id numberOfBits,
vtkm::cont::internal::Buffer* buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
const vtkm::Id bytesNeeded = (numberOfBits + CHAR_BIT - 1) / CHAR_BIT;
const vtkm::Id blocksNeeded = (bytesNeeded + BlockSize - 1) / BlockSize;
@ -104,29 +102,29 @@ public:
vtkm::cont::detail::GetBitFieldMetaData(buffers[0])->NumberOfBits = numberOfBits;
}
VTKM_CONT vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
{
vtkm::Id numberOfBits = vtkm::cont::detail::GetBitFieldMetaData(buffers[0])->NumberOfBits;
VTKM_ASSERT((buffers[0].GetNumberOfBytes() * CHAR_BIT) >= numberOfBits);
return numberOfBits;
}
VTKM_CONT ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
vtkm::Id numberOfBits = this->GetNumberOfValues(buffers);
vtkm::Id numberOfBits = GetNumberOfValues(buffers);
VTKM_ASSERT((buffers[0].GetNumberOfBytes() * CHAR_BIT) >= numberOfBits);
return ReadPortalType(
BitPortalConstType(buffers[0].ReadPointerDevice(device, token), numberOfBits));
}
VTKM_CONT WritePortalType CreateWritePortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static WritePortalType CreateWritePortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
vtkm::Id numberOfBits = this->GetNumberOfValues(buffers);
vtkm::Id numberOfBits = GetNumberOfValues(buffers);
VTKM_ASSERT((buffers[0].GetNumberOfBytes() * CHAR_BIT) >= numberOfBits);
return WritePortalType(

@ -142,12 +142,12 @@ public:
using WritePortalType =
vtkm::internal::ArrayPortalSOA<T, vtkm::internal::ArrayPortalBasicWrite<ComponentType>>;
VTKM_CONT vtkm::IdComponent GetNumberOfBuffers() const { return NUM_COMPONENTS; }
VTKM_CONT static vtkm::IdComponent GetNumberOfBuffers() { return NUM_COMPONENTS; }
VTKM_CONT void ResizeBuffers(vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
vtkm::BufferSizeType numBytes =
vtkm::internal::NumberOfValuesToNumberOfBytes<ComponentType>(numValues);
@ -157,18 +157,18 @@ public:
}
}
VTKM_CONT vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
{
// Assume all buffers are the same size.
return static_cast<vtkm::Id>(buffers[0].GetNumberOfBytes()) /
static_cast<vtkm::Id>(sizeof(ComponentType));
}
VTKM_CONT ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
vtkm::Id numValues = this->GetNumberOfValues(buffers);
vtkm::Id numValues = GetNumberOfValues(buffers);
ReadPortalType portal(numValues);
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; ++componentIndex)
{
@ -182,11 +182,11 @@ public:
return portal;
}
VTKM_CONT WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
vtkm::Id numValues = this->GetNumberOfValues(buffers);
vtkm::Id numValues = GetNumberOfValues(buffers);
WritePortalType portal(numValues);
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; ++componentIndex)
{