Geometry Nodes: avoid allocation when construct varray for single value

Previously, `GVArray::ForSingle` would always allocate a copy of the passed
in value. Now it only does so when the value is too large or not trivial.
This commit is contained in:
Jacques Lucke 2021-11-26 09:59:41 +01:00
parent 8015433f81
commit 2cda65a35a
2 changed files with 66 additions and 0 deletions

View File

@ -207,6 +207,18 @@ class CPPType : NonCopyable, NonMovable {
return is_trivially_destructible_;
}
/**
* When true, the value is like a normal C type, it can be copied around with #memcpy and does
* not have to be destructed.
*
* C++ equivalent:
* std::is_trivial_v<T>;
*/
bool is_trivial() const
{
return is_trivial_;
}
bool is_default_constructible() const
{
return default_construct_ != nullptr;

View File

@ -336,6 +336,57 @@ class GVArrayImpl_For_SingleValue : public GVArrayImpl_For_SingleValueRef,
/** \} */
/* -------------------------------------------------------------------- */
/** \name #GVArrayImpl_For_SmallTrivialSingleValue
* \{ */
/**
* Contains an inline buffer that can store a single value of a trivial type.
* This avoids the allocation that would be done by #GVArrayImpl_For_SingleValue.
*/
template<int BufferSize> class GVArrayImpl_For_SmallTrivialSingleValue : public GVArrayImpl {
private:
AlignedBuffer<BufferSize, 8> buffer_;
public:
GVArrayImpl_For_SmallTrivialSingleValue(const CPPType &type,
const int64_t size,
const void *value)
: GVArrayImpl(type, size)
{
BLI_assert(type.is_trivial());
BLI_assert(type.alignment() <= 8);
BLI_assert(type.size() <= BufferSize);
type.copy_construct(value, &buffer_);
}
private:
void get(const int64_t UNUSED(index), void *r_value) const override
{
this->copy_value_to(r_value);
}
void get_to_uninitialized(const int64_t UNUSED(index), void *r_value) const override
{
this->copy_value_to(r_value);
}
bool is_single() const override
{
return true;
}
void get_internal_single(void *r_value) const override
{
this->copy_value_to(r_value);
}
void copy_value_to(void *dst) const
{
memcpy(dst, &buffer_, type_->size());
}
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name #GVArray_GSpan
* \{ */
@ -593,6 +644,9 @@ GVArray::GVArray(std::shared_ptr<const GVArrayImpl> impl) : GVArrayCommon(std::m
GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value)
{
if (type.is_trivial() && type.size() <= 16 && type.alignment() <= 8) {
return GVArray::For<GVArrayImpl_For_SmallTrivialSingleValue<16>>(type, size, value);
}
return GVArray::For<GVArrayImpl_For_SingleValue>(type, size, value);
}