Simplify creating metadata in Buffer objects

Previously you had to create a special virtual object to place in the
`Buffer`'s metadata. This added a lot of difficulty that is probably
unnecessary.

Instead, just have `Buffer` hold an arbitrary object and some simple
functions to copy and delete it. There may be issues with type safety
across translation units, but we'll deal with that when/if we run into
it.
This commit is contained in:
Kenneth Moreland 2020-11-10 16:22:05 -07:00
parent 132a07225d
commit 2f04dc3aef
11 changed files with 177 additions and 318 deletions

@ -99,12 +99,13 @@ public:
vtkm::cont::GetSizeString(static_cast<vtkm::UInt64>(numBytes)).c_str());
buffers[0].SetNumberOfBytes(numBytes, preserve, token);
vtkm::cont::detail::GetBitFieldMetaData(buffers[0])->NumberOfBits = numberOfBits;
buffers[0].GetMetaData<vtkm::cont::internal::BitFieldMetaData>().NumberOfBits = numberOfBits;
}
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
{
vtkm::Id numberOfBits = vtkm::cont::detail::GetBitFieldMetaData(buffers[0])->NumberOfBits;
vtkm::Id numberOfBits =
buffers[0].GetMetaData<vtkm::cont::internal::BitFieldMetaData>().NumberOfBits;
VTKM_ASSERT((buffers[0].GetNumberOfBytes() * CHAR_BIT) >= numberOfBits);
return numberOfBits;
}

@ -1,45 +0,0 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/ArrayHandleDiscard.h>
namespace vtkm
{
namespace cont
{
namespace internal
{
BufferMetaDataDiscard::~BufferMetaDataDiscard() = default;
std::unique_ptr<vtkm::cont::internal::BufferMetaData> BufferMetaDataDiscard::DeepCopy() const
{
return std::unique_ptr<vtkm::cont::internal::BufferMetaData>(new BufferMetaDataDiscard(*this));
}
vtkm::cont::internal::BufferMetaDataDiscard* GetDiscardMetaData(
const vtkm::cont::internal::Buffer& buffer)
{
vtkm::cont::internal::BufferMetaData* generalMetadata = buffer.GetMetaData();
if (generalMetadata == nullptr)
{
buffer.SetMetaData(vtkm::cont::internal::BufferMetaDataDiscard{});
generalMetadata = buffer.GetMetaData();
}
vtkm::cont::internal::BufferMetaDataDiscard* metadata =
dynamic_cast<vtkm::cont::internal::BufferMetaDataDiscard*>(buffer.GetMetaData());
VTKM_ASSERT(metadata && "Buffer for discard array does not have correct metadata.");
return metadata;
}
}
}
} // namespace vtkm::cont::internal

@ -88,18 +88,11 @@ struct VTKM_ALWAYS_EXPORT StorageTagDiscard
{
};
struct VTKM_CONT_EXPORT BufferMetaDataDiscard : vtkm::cont::internal::BufferMetaData
struct VTKM_ALWAYS_EXPORT DiscardMetaData
{
vtkm::Id NumberOfValues = 0;
VTKM_CONT ~BufferMetaDataDiscard() override;
VTKM_CONT std::unique_ptr<vtkm::cont::internal::BufferMetaData> DeepCopy() const override;
};
VTKM_CONT_EXPORT vtkm::cont::internal::BufferMetaDataDiscard* GetDiscardMetaData(
const vtkm::cont::internal::Buffer& buffer);
template <typename ValueType>
class Storage<ValueType, StorageTagDiscard>
{
@ -118,12 +111,12 @@ public:
vtkm::cont::Token&)
{
VTKM_ASSERT(numValues >= 0);
vtkm::cont::internal::GetDiscardMetaData(buffers[0])->NumberOfValues = numValues;
buffers[0].GetMetaData<DiscardMetaData>().NumberOfValues = numValues;
}
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
{
return vtkm::cont::internal::GetDiscardMetaData(buffers[0])->NumberOfValues;
return buffers[0].GetMetaData<DiscardMetaData>().NumberOfValues;
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer*,

@ -1,75 +0,0 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/ArrayHandleImplicit.h>
namespace vtkm
{
namespace cont
{
namespace internal
{
BufferMetaDataImplicit::BufferMetaDataImplicit(const BufferMetaDataImplicit& src)
: Deleter(src.Deleter)
, Copier(src.Copier)
{
if (src.Portal)
{
VTKM_ASSERT(src.Deleter);
VTKM_ASSERT(src.Copier);
this->Portal = src.Copier(src.Portal);
}
else
{
this->Portal = nullptr;
}
}
BufferMetaDataImplicit::~BufferMetaDataImplicit()
{
if (this->Portal)
{
VTKM_ASSERT(this->Deleter);
this->Deleter(this->Portal);
this->Portal = nullptr;
}
}
std::unique_ptr<vtkm::cont::internal::BufferMetaData> BufferMetaDataImplicit::DeepCopy() const
{
return std::unique_ptr<vtkm::cont::internal::BufferMetaData>(new BufferMetaDataImplicit(*this));
}
namespace detail
{
vtkm::cont::internal::BufferMetaDataImplicit* GetImplicitMetaData(
const vtkm::cont::internal::Buffer& buffer)
{
vtkm::cont::internal::BufferMetaDataImplicit* metadata =
dynamic_cast<vtkm::cont::internal::BufferMetaDataImplicit*>(buffer.GetMetaData());
VTKM_ASSERT(metadata && "Buffer for implicit array does not have correct metadata.");
return metadata;
}
} // namespace detail
}
}
} // namespace vtkm::cont::internal
namespace vtkm
{
namespace cont
{
}
} // namespace vtkm::cont::detail

@ -91,41 +91,6 @@ struct VTKM_ALWAYS_EXPORT StorageTagImplicit
namespace internal
{
struct VTKM_CONT_EXPORT BufferMetaDataImplicit : vtkm::cont::internal::BufferMetaData
{
void* Portal;
using DeleterType = void(void*);
DeleterType* Deleter;
using CopierType = void*(void*);
CopierType* Copier;
template <typename PortalType>
BufferMetaDataImplicit(const PortalType& portal)
: Portal(new PortalType(portal))
, Deleter([](void* p) { delete reinterpret_cast<PortalType*>(p); })
, Copier([](void* p) -> void* { return new PortalType(*reinterpret_cast<PortalType*>(p)); })
{
}
VTKM_CONT BufferMetaDataImplicit(const BufferMetaDataImplicit& src);
BufferMetaDataImplicit& operator=(const BufferMetaDataImplicit&) = delete;
VTKM_CONT ~BufferMetaDataImplicit() override;
VTKM_CONT std::unique_ptr<vtkm::cont::internal::BufferMetaData> DeepCopy() const override;
};
namespace detail
{
VTKM_CONT_EXPORT vtkm::cont::internal::BufferMetaDataImplicit* GetImplicitMetaData(
const vtkm::cont::internal::Buffer& buffer);
} // namespace detail
template <class ArrayPortalType>
struct VTKM_ALWAYS_EXPORT
Storage<typename ArrayPortalType::ValueType, StorageTagImplicit<ArrayPortalType>>
@ -144,10 +109,7 @@ struct VTKM_ALWAYS_EXPORT
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
{
vtkm::cont::internal::BufferMetaDataImplicit* metadata =
detail::GetImplicitMetaData(buffers[0]);
VTKM_ASSERT(metadata->Portal);
return reinterpret_cast<ArrayPortalType*>(metadata->Portal)->GetNumberOfValues();
return buffers[0].GetMetaData<ArrayPortalType>().GetNumberOfValues();
}
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
@ -170,10 +132,7 @@ struct VTKM_ALWAYS_EXPORT
vtkm::cont::DeviceAdapterId,
vtkm::cont::Token&)
{
vtkm::cont::internal::BufferMetaDataImplicit* metadata =
detail::GetImplicitMetaData(buffers[0]);
VTKM_ASSERT(metadata->Portal);
return *reinterpret_cast<ReadPortalType*>(metadata->Portal);
return buffers[0].GetMetaData<ArrayPortalType>();
}
VTKM_CONT static WritePortalType CreateWritePortal(const vtkm::cont::internal::Buffer*,
@ -191,8 +150,7 @@ VTKM_CONT inline std::vector<vtkm::cont::internal::Buffer> PortalToArrayHandleIm
const PortalType& portal)
{
std::vector<vtkm::cont::internal::Buffer> buffers(1);
buffers[0].SetMetaData(std::unique_ptr<vtkm::cont::internal::BufferMetaData>(
new vtkm::cont::internal::BufferMetaDataImplicit(portal)));
buffers[0].SetMetaData(portal);
return buffers;
}

@ -41,62 +41,16 @@ namespace cont
namespace detail
{
vtkm::cont::internal::BufferMetaDataBitField* GetBitFieldMetaData(
const vtkm::cont::internal::Buffer& buffer)
{
vtkm::cont::internal::BufferMetaData* generalMetaData = buffer.GetMetaData();
if (generalMetaData == nullptr)
{
VTKM_LOG_F(vtkm::cont::LogLevel::Warn, "BitField has buffer with no metadata. Setting.");
const_cast<vtkm::cont::internal::Buffer&>(buffer).SetMetaData(
vtkm::cont::internal::BufferMetaDataBitField{});
generalMetaData = buffer.GetMetaData();
VTKM_ASSERT(generalMetaData != nullptr);
}
vtkm::cont::internal::BufferMetaDataBitField* metadata =
dynamic_cast<vtkm::cont::internal::BufferMetaDataBitField*>(generalMetaData);
if (metadata == nullptr)
{
VTKM_LOG_F(vtkm::cont::LogLevel::Error,
"BitField has a buffer with metadata of the wrong type. "
"Replacing, but this will likely cause problems.");
const_cast<vtkm::cont::internal::Buffer&>(buffer).SetMetaData(
vtkm::cont::internal::BufferMetaDataBitField{});
generalMetaData = buffer.GetMetaData();
metadata = dynamic_cast<vtkm::cont::internal::BufferMetaDataBitField*>(generalMetaData);
VTKM_ASSERT(metadata != nullptr);
}
// Check to make sure that the buffer is at least as larger as needed for buffer size.
VTKM_ASSERT(buffer.GetNumberOfBytes() * CHAR_BIT >= metadata->NumberOfBits);
return metadata;
}
} // namespace detail
namespace internal
{
BufferMetaDataBitField::~BufferMetaDataBitField() {}
std::unique_ptr<vtkm::cont::internal::BufferMetaData> BufferMetaDataBitField::DeepCopy() const
{
return std::unique_ptr<vtkm::cont::internal::BufferMetaData>(new BufferMetaDataBitField(*this));
}
} // namespace internal
BitField::BitField()
{
this->Buffer.SetMetaData(internal::BufferMetaDataBitField{});
this->Buffer.SetMetaData(internal::BitFieldMetaData{});
}
vtkm::Id BitField::GetNumberOfBits() const
{
auto metadata = detail::GetBitFieldMetaData(this->Buffer);
return metadata->NumberOfBits;
return this->Buffer.GetMetaData<internal::BitFieldMetaData>().NumberOfBits;
}
void BitField::Allocate(vtkm::Id numberOfBits,
@ -113,7 +67,7 @@ void BitField::Allocate(vtkm::Id numberOfBits,
vtkm::cont::GetSizeString(static_cast<vtkm::UInt64>(numBytes)).c_str());
this->Buffer.SetNumberOfBytes(numBytes, preserve, token);
detail::GetBitFieldMetaData(this->Buffer)->NumberOfBits = numberOfBits;
this->Buffer.GetMetaData<internal::BitFieldMetaData>().NumberOfBits = numberOfBits;
}
void BitField::ReleaseResourcesExecution()
@ -125,7 +79,7 @@ void BitField::ReleaseResources()
{
vtkm::cont::Token token;
this->Buffer.SetNumberOfBytes(0, vtkm::CopyFlag::Off, token);
detail::GetBitFieldMetaData(this->Buffer)->NumberOfBits = 0;
this->Buffer.GetMetaData<internal::BitFieldMetaData>().NumberOfBits = 0;
}
void BitField::SyncControlArray() const
@ -150,21 +104,21 @@ BitField::WritePortalType BitField::WritePortal() const
{
vtkm::cont::Token token;
return WritePortalType(this->Buffer.WritePointerHost(token),
detail::GetBitFieldMetaData(this->Buffer)->NumberOfBits);
this->Buffer.GetMetaData<internal::BitFieldMetaData>().NumberOfBits);
}
BitField::ReadPortalType BitField::ReadPortal() const
{
vtkm::cont::Token token;
return ReadPortalType(this->Buffer.ReadPointerHost(token),
detail::GetBitFieldMetaData(this->Buffer)->NumberOfBits);
this->Buffer.GetMetaData<internal::BitFieldMetaData>().NumberOfBits);
}
BitField::ReadPortalType BitField::PrepareForInput(vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token) const
{
return ReadPortalType(this->Buffer.ReadPointerDevice(device, token),
detail::GetBitFieldMetaData(this->Buffer)->NumberOfBits);
this->Buffer.GetMetaData<internal::BitFieldMetaData>().NumberOfBits);
}
BitField::WritePortalType BitField::PrepareForOutput(vtkm::Id numBits,
@ -173,14 +127,14 @@ BitField::WritePortalType BitField::PrepareForOutput(vtkm::Id numBits,
{
this->Allocate(numBits, vtkm::CopyFlag::Off, token);
return WritePortalType(this->Buffer.WritePointerDevice(device, token),
detail::GetBitFieldMetaData(this->Buffer)->NumberOfBits);
this->Buffer.GetMetaData<internal::BitFieldMetaData>().NumberOfBits);
}
BitField::WritePortalType BitField::PrepareForInPlace(vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token) const
{
return WritePortalType(this->Buffer.WritePointerDevice(device, token),
detail::GetBitFieldMetaData(this->Buffer)->NumberOfBits);
this->Buffer.GetMetaData<internal::BitFieldMetaData>().NumberOfBits);
}
}

@ -36,13 +36,9 @@ namespace internal
struct StorageTagBitField;
struct VTKM_CONT_EXPORT BufferMetaDataBitField : vtkm::cont::internal::BufferMetaData
struct VTKM_ALWAYS_EXPORT BitFieldMetaData
{
vtkm::Id NumberOfBits = 0;
VTKM_CONT ~BufferMetaDataBitField() override;
VTKM_CONT std::unique_ptr<vtkm::cont::internal::BufferMetaData> DeepCopy() const override;
};
}
@ -99,9 +95,6 @@ struct BitCoordinate
vtkm::Int32 BitOffset; // [0, bitsInWord)
};
VTKM_CONT_EXPORT vtkm::cont::internal::BufferMetaDataBitField* GetBitFieldMetaData(
const vtkm::cont::internal::Buffer& buffer);
/// Portal for performing bit or word operations on a BitField.
///
/// This is the implementation used by BitPortal and BitPortalConst.

@ -135,8 +135,6 @@ set(template_sources
set(sources
ArrayHandle.cxx
ArrayHandleBasic.cxx
ArrayHandleDiscard.cxx
ArrayHandleImplicit.cxx
ArrayHandleSOA.cxx
BitField.cxx
ColorTablePresets.cxx

@ -12,6 +12,7 @@
#include <vtkm/cont/ErrorBadAllocation.h>
#include <vtkm/cont/ErrorBadDevice.h>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/RuntimeDeviceInformation.h>
#include <vtkm/cont/internal/Buffer.h>
@ -100,6 +101,71 @@ struct BufferState
}
};
struct MetaDataManager
{
void* Data = nullptr;
std::string Type;
vtkm::cont::internal::detail::DeleterType* Deleter = nullptr;
vtkm::cont::internal::detail::CopierType* Copier = nullptr;
MetaDataManager() = default;
MetaDataManager(void* data,
const std::string& type,
vtkm::cont::internal::detail::DeleterType* deleter,
vtkm::cont::internal::detail::CopierType* copier)
: Data(data)
, Type(type)
, Deleter(deleter)
, Copier(copier)
{
}
~MetaDataManager()
{
if (this->Data != nullptr)
{
VTKM_ASSERT(this->Deleter != nullptr);
this->Deleter(this->Data);
this->Data = nullptr;
}
}
MetaDataManager(const MetaDataManager& src)
{
if (src.Data != nullptr)
{
VTKM_ASSERT(src.Copier);
VTKM_ASSERT(src.Deleter);
this->Data = src.Copier(src.Data);
this->Type = src.Type;
this->Deleter = src.Deleter;
this->Copier = src.Copier;
}
}
MetaDataManager& operator=(const MetaDataManager& src)
{
if (this->Data != nullptr)
{
VTKM_ASSERT(this->Deleter != nullptr);
this->Deleter(this->Data);
this->Data = nullptr;
this->Type = "";
}
if (src.Data != nullptr)
{
VTKM_ASSERT(src.Copier);
VTKM_ASSERT(src.Deleter);
this->Data = src.Copier(src.Data);
this->Type = src.Type;
this->Deleter = src.Deleter;
this->Copier = src.Copier;
}
return *this;
}
};
} // anonymous namespace
namespace vtkm
@ -109,8 +175,6 @@ namespace cont
namespace internal
{
BufferMetaData::~BufferMetaData() {}
class Buffer::InternalsStruct
{
public:
@ -138,7 +202,7 @@ public:
std::mutex Mutex;
std::condition_variable ConditionVariable;
std::unique_ptr<vtkm::cont::internal::BufferMetaData> MetaData;
MetaDataManager MetaData;
LockType GetLock() { return LockType(this->Mutex); }
@ -535,10 +599,7 @@ struct VTKM_NEVER_EXPORT BufferHelper
srcInternals->GetHostBuffer(srcLock).GetPointer(),
static_cast<std::size_t>(size));
if (srcInternals->MetaData)
{
destInternals->MetaData = srcInternals->MetaData->DeepCopy();
}
destInternals->MetaData = srcInternals->MetaData;
}
static void CopyOnDevice(
@ -580,10 +641,7 @@ struct VTKM_NEVER_EXPORT BufferHelper
destInternals->SetNumberOfBytes(destLock, srcInternals->GetNumberOfBytes(srcLock));
if (srcInternals->MetaData)
{
destInternals->MetaData = srcInternals->MetaData->DeepCopy();
}
destInternals->MetaData = srcInternals->MetaData;
}
};
@ -637,14 +695,31 @@ void Buffer::SetNumberOfBytes(vtkm::BufferSizeType numberOfBytes,
detail::BufferHelper::SetNumberOfBytes(this->Internals, lock, numberOfBytes, preserve, token);
}
vtkm::cont::internal::BufferMetaData* Buffer::GetMetaData() const
bool Buffer::HasMetaData() const
{
return this->Internals->MetaData.get();
return (this->Internals->MetaData.Data != nullptr);
}
void Buffer::SetMetaData(std::unique_ptr<vtkm::cont::internal::BufferMetaData>&& metadata) const
bool Buffer::MetaDataIsType(const std::string& type) const
{
this->Internals->MetaData = std::move(metadata);
return this->HasMetaData() && (this->Internals->MetaData.Type == type);
}
void Buffer::SetMetaData(void* data,
const std::string& type,
detail::DeleterType* deleter,
detail::CopierType* copier) const
{
this->Internals->MetaData = MetaDataManager(data, type, deleter, copier);
}
void* Buffer::GetMetaData(const std::string& type) const
{
if (type != this->Internals->MetaData.Type)
{
throw vtkm::cont::ErrorBadType("Requesting Buffer meta data that is the wrong type.");
}
return this->Internals->MetaData.Data;
}
bool Buffer::IsAllocatedOnHost() const
@ -806,10 +881,7 @@ void Buffer::DeepCopyFrom(const vtkm::cont::internal::Buffer& src) const
src.Internals->GetNumberOfBytes(srcLock),
vtkm::CopyFlag::Off,
token);
if (src.Internals->MetaData)
{
dest.Internals->MetaData = src.Internals->MetaData->DeepCopy();
}
dest.Internals->MetaData = src.Internals->MetaData;
}
}
}

@ -13,6 +13,7 @@
#include <vtkm/cont/vtkm_cont_export.h>
#include <vtkm/cont/DeviceAdapterTag.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/Serialization.h>
#include <vtkm/cont/Token.h>
@ -59,29 +60,23 @@ namespace detail
struct BufferHelper;
} // namespace detail
using DeleterType = void(void*);
/// \brief An object to hold metadata for a `Buffer` object.
///
/// A `Buffer` object can optionally hold a `BufferMetaData` object. The metadata object
/// allows the buffer to hold state for the buffer that is not directly related to the
/// memory allocated and its size. This allows you to completely encapsulate the state
/// in the `Buffer` object and then pass the `Buffer` object to different object that
/// provide different interfaces to the array.
///
/// To use `BufferMetaData`, create a subclass, and then provide that subclass as the
/// metadata. The `Buffer` object will only remember it as the generic base class. You
/// can then get the metadata and perform a `dynamic_cast` to check that the metadata
/// is as expected and to get to the meta information
///
struct VTKM_CONT_EXPORT BufferMetaData
template <typename T>
void BasicDeleter(void* mem)
{
virtual ~BufferMetaData();
T* obj = reinterpret_cast<T*>(mem);
delete obj;
}
/// Subclasses must provide a way to deep copy metadata.
///
virtual std::unique_ptr<BufferMetaData> DeepCopy() const = 0;
};
using CopierType = void*(const void*);
template <typename T>
void* BasicCopier(const void* mem)
{
return new T(*reinterpret_cast<const T*>(mem));
}
} // namespace detail
/// \brief Manages a buffer data among the host and various devices.
///
@ -130,34 +125,65 @@ public:
vtkm::CopyFlag preserve,
vtkm::cont::Token& token);
/// \brief Gets the metadata for the buffer.
private:
VTKM_CONT bool MetaDataIsType(const std::string& type) const;
VTKM_CONT void SetMetaData(void* data,
const std::string& type,
detail::DeleterType* deleter,
detail::CopierType copier) const;
VTKM_CONT void* GetMetaData(const std::string& type) const;
public:
/// \brief Returns whether this `Buffer` holds metadata.
///
/// Holding metadata in a `Buffer` is optional. The metadata is held in a subclass of
/// `BufferMetaData`, and you will have to safely downcast the object to retrieve the
/// actual information.
VTKM_CONT bool HasMetaData() const;
/// \brief Determines if the metadata for the buffer is set to the given type.
///
/// The metadata could be a `nullptr` if the metadata was never set.
///
VTKM_CONT vtkm::cont::internal::BufferMetaData* GetMetaData() const;
template <typename MetaDataType>
VTKM_CONT bool MetaDataIsType() const
{
return this->MetaDataIsType(vtkm::cont::TypeToString<MetaDataType>());
}
/// \brief Sets the metadata for the buffer.
///
/// This form of SetMetaData takes an rvalue to a unique_ptr holding the metadata to
/// ensure that the object is properly managed.
/// Takes an arbitrary object and copies it to the metadata of this buffer. Any existing
/// metadata is deleted. Any object can be set as the metadata as long as the object has
/// a default constructor and is copyable.
///
VTKM_CONT void SetMetaData(
std::unique_ptr<vtkm::cont::internal::BufferMetaData>&& metadata) const;
/// \brief Sets the metadata for the buffer.
///
/// This form of SetMetaData takes the metadata object value. The metadata object
/// must be a subclass of BufferMetaData or you will get a compile error.
/// Holding metadata in a `Buffer` is optional, but helpful for storing additional
/// information or objects that cannot be implied by the buffer itself.
///
template <typename MetaDataType>
VTKM_CONT void SetMetaData(const MetaDataType& metadata) const
{
this->SetMetaData(
std::unique_ptr<vtkm::cont::internal::BufferMetaData>(new MetaDataType(metadata)));
MetaDataType* metadataCopy = new MetaDataType(metadata);
this->SetMetaData(metadataCopy,
vtkm::cont::TypeToString(metadata),
detail::BasicDeleter<MetaDataType>,
detail::BasicCopier<MetaDataType>);
}
/// \brief Gets the metadata for the buffer.
///
/// When you call this method, you have to specify a template parameter for the type
/// of the metadata. If the metadata has not yet been set in this buffer, a new metadata
/// object is created, set to this buffer, and returned. If metadata of a different type
/// has already been set, then an exception is thrown.
///
/// The returned value is a reference that can be manipulated to alter the metadata of
/// this buffer.
///
template <typename MetaDataType>
VTKM_CONT MetaDataType& GetMetaData() const
{
if (!this->HasMetaData())
{
this->SetMetaData(MetaDataType{});
}
return *reinterpret_cast<MetaDataType*>(
this->GetMetaData(vtkm::cont::TypeToString<MetaDataType>()));
}
/// \brief Returns `true` if the buffer is allocated on the host.

@ -23,32 +23,16 @@ constexpr vtkm::Id ARRAY_SIZE = 20;
using PortalType = vtkm::cont::internal::ArrayPortalFromIterators<T*>;
using PortalTypeConst = vtkm::cont::internal::ArrayPortalFromIterators<const T*>;
struct BufferMetaDataTest : vtkm::cont::internal::BufferMetaData
struct TestMetaData
{
vtkm::Id Value;
std::unique_ptr<vtkm::cont::internal::BufferMetaData> DeepCopy() const override
{
return std::unique_ptr<vtkm::cont::internal::BufferMetaData>(new BufferMetaDataTest(*this));
}
};
constexpr vtkm::Id METADATA_VALUE = 42;
bool CheckMetaData(const vtkm::cont::internal::Buffer& buffer)
{
vtkm::cont::internal::BufferMetaData* generalMetaData = buffer.GetMetaData();
if (!generalMetaData)
{
return false;
}
BufferMetaDataTest* metadata = dynamic_cast<BufferMetaDataTest*>(generalMetaData);
if (!metadata)
{
return false;
}
return metadata->Value == METADATA_VALUE;
return buffer.GetMetaData<TestMetaData>().Value == METADATA_VALUE;
}
PortalType MakePortal(void* buffer, vtkm::Id numValues)
@ -110,7 +94,7 @@ void DoTest()
vtkm::cont::internal::Buffer buffer;
{
BufferMetaDataTest metadata;
TestMetaData metadata;
metadata.Value = METADATA_VALUE;
buffer.SetMetaData(metadata);
VTKM_TEST_ASSERT(CheckMetaData(buffer));