Files
test2/source/blender/blenlib/BLI_generic_virtual_array.hh
Jacques Lucke 5c80bcf8c2 Functions: speedup preparing multi-function parameters
My benchmark which spend most time preparing function parameters
takes `250 ms` now, from `510 ms` before. This is mainly achieved by
doing less unnecessary work and by giving the compiler more inlined
code to optimize.

* Reserve correct vector sizes and use unchecked `append` function.
* Construct `GVArray` parameters directly in the vector, instead of
  moving/copying them in the vector afterwards.
* Inline some constructors, because that allows the compiler understand
  what is happening, resulting in less code.

This probably has negilible impact on the user experience currently,
because there are other bottlenecks.

Differential Revision: https://developer.blender.org/D15009
2022-05-31 20:41:01 +02:00

1038 lines
28 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup bli
*
* A generic virtual array is the same as a virtual array, except for the fact that the data type
* is only known at runtime.
*/
#include "BLI_generic_array.hh"
#include "BLI_generic_span.hh"
#include "BLI_timeit.hh"
#include "BLI_virtual_array.hh"
namespace blender {
/* -------------------------------------------------------------------- */
/** \name #GVArrayImpl and #GVMutableArrayImpl.
* \{ */
class GVArray;
class GVArrayImpl;
class GVMutableArray;
class GVMutableArrayImpl;
/* A generically typed version of #VArrayImpl. */
class GVArrayImpl {
protected:
const CPPType *type_;
int64_t size_;
public:
GVArrayImpl(const CPPType &type, int64_t size);
virtual ~GVArrayImpl() = default;
const CPPType &type() const;
int64_t size() const;
virtual void get(int64_t index, void *r_value) const;
virtual void get_to_uninitialized(int64_t index, void *r_value) const = 0;
virtual bool is_span() const;
virtual GSpan get_internal_span() const;
virtual bool is_single() const;
virtual void get_internal_single(void *UNUSED(r_value)) const;
virtual void materialize(const IndexMask mask, void *dst) const;
virtual void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
virtual void materialize_compressed(IndexMask mask, void *dst) const;
virtual void materialize_compressed_to_uninitialized(IndexMask mask, void *dst) const;
virtual bool try_assign_VArray(void *varray) const;
virtual bool may_have_ownership() const;
};
/* A generic version of #VMutableArrayImpl. */
class GVMutableArrayImpl : public GVArrayImpl {
public:
GVMutableArrayImpl(const CPPType &type, int64_t size) : GVArrayImpl(type, size)
{
}
virtual void set_by_copy(int64_t index, const void *value);
virtual void set_by_relocate(int64_t index, void *value);
virtual void set_by_move(int64_t index, void *value) = 0;
virtual void set_all(const void *src);
virtual bool try_assign_VMutableArray(void *varray) const;
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name #GVArray and #GVMutableArray
* \{ */
namespace detail {
struct GVArrayAnyExtraInfo {
const GVArrayImpl *(*get_varray)(const void *buffer) =
[](const void *UNUSED(buffer)) -> const GVArrayImpl * { return nullptr; };
template<typename StorageT> static constexpr GVArrayAnyExtraInfo get();
};
} // namespace detail
class GVMutableArray;
/**
* Utility class to reduce code duplication between #GVArray and #GVMutableArray.
* It pretty much follows #VArrayCommon. Don't use this class outside of this header.
*/
class GVArrayCommon {
protected:
/**
* See #VArrayCommon for more information. The inline buffer is a bit larger here, because
* generic virtual array implementations often require a bit more space than typed ones.
*/
using Storage = Any<detail::GVArrayAnyExtraInfo, 40, 8>;
const GVArrayImpl *impl_ = nullptr;
Storage storage_;
protected:
GVArrayCommon() = default;
GVArrayCommon(const GVArrayCommon &other);
GVArrayCommon(GVArrayCommon &&other) noexcept;
GVArrayCommon(const GVArrayImpl *impl);
GVArrayCommon(std::shared_ptr<const GVArrayImpl> impl);
~GVArrayCommon();
template<typename ImplT, typename... Args> void emplace(Args &&...args);
void copy_from(const GVArrayCommon &other);
void move_from(GVArrayCommon &&other) noexcept;
const GVArrayImpl *impl_from_storage() const;
public:
const CPPType &type() const;
operator bool() const;
int64_t size() const;
bool is_empty() const;
IndexRange index_range() const;
template<typename T> bool try_assign_VArray(VArray<T> &varray) const;
bool may_have_ownership() const;
void materialize(void *dst) const;
void materialize(const IndexMask mask, void *dst) const;
void materialize_to_uninitialized(void *dst) const;
void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
void materialize_compressed(IndexMask mask, void *dst) const;
void materialize_compressed_to_uninitialized(IndexMask mask, void *dst) const;
/**
* Returns true when the virtual array is stored as a span internally.
*/
bool is_span() const;
/**
* Returns the internally used span of the virtual array. This invokes undefined behavior if the
* virtual array is not stored as a span internally.
*/
GSpan get_internal_span() const;
/**
* Returns true when the virtual array returns the same value for every index.
*/
bool is_single() const;
/**
* Copies the value that is used for every element into `r_value`, which is expected to point to
* initialized memory. This invokes undefined behavior if the virtual array would not return the
* same value for every index.
*/
void get_internal_single(void *r_value) const;
/**
* Same as `get_internal_single`, but `r_value` points to initialized memory.
*/
void get_internal_single_to_uninitialized(void *r_value) const;
void get(int64_t index, void *r_value) const;
/**
* Returns a copy of the value at the given index. Usually a typed virtual array should
* be used instead, but sometimes this is simpler when only a few indices are needed.
*/
template<typename T> T get(int64_t index) const;
void get_to_uninitialized(int64_t index, void *r_value) const;
};
/** Generic version of #VArray. */
class GVArray : public GVArrayCommon {
private:
friend GVMutableArray;
public:
GVArray() = default;
GVArray(const GVArray &other);
GVArray(GVArray &&other) noexcept;
GVArray(const GVArrayImpl *impl);
GVArray(std::shared_ptr<const GVArrayImpl> impl);
GVArray(varray_tag::span /* tag */, GSpan span);
GVArray(varray_tag::single_ref /* tag */, const CPPType &type, int64_t size, const void *value);
GVArray(varray_tag::single /* tag */, const CPPType &type, int64_t size, const void *value);
template<typename T> GVArray(const VArray<T> &varray);
template<typename T> VArray<T> typed() const;
template<typename ImplT, typename... Args> static GVArray For(Args &&...args);
static GVArray ForSingle(const CPPType &type, int64_t size, const void *value);
static GVArray ForSingleRef(const CPPType &type, int64_t size, const void *value);
static GVArray ForSingleDefault(const CPPType &type, int64_t size);
static GVArray ForSpan(GSpan span);
static GVArray ForGArray(GArray<> array);
static GVArray ForEmpty(const CPPType &type);
GVArray slice(IndexRange slice) const;
GVArray &operator=(const GVArray &other);
GVArray &operator=(GVArray &&other) noexcept;
const GVArrayImpl *get_implementation() const
{
return impl_;
}
};
/** Generic version of #VMutableArray. */
class GVMutableArray : public GVArrayCommon {
public:
GVMutableArray() = default;
GVMutableArray(const GVMutableArray &other);
GVMutableArray(GVMutableArray &&other) noexcept;
GVMutableArray(GVMutableArrayImpl *impl);
GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl);
template<typename T> GVMutableArray(const VMutableArray<T> &varray);
template<typename T> VMutableArray<T> typed() const;
template<typename ImplT, typename... Args> static GVMutableArray For(Args &&...args);
static GVMutableArray ForSpan(GMutableSpan span);
operator GVArray() const &;
operator GVArray() &&noexcept;
GVMutableArray &operator=(const GVMutableArray &other);
GVMutableArray &operator=(GVMutableArray &&other) noexcept;
GMutableSpan get_internal_span() const;
template<typename T> bool try_assign_VMutableArray(VMutableArray<T> &varray) const;
void set_by_copy(int64_t index, const void *value);
void set_by_move(int64_t index, void *value);
void set_by_relocate(int64_t index, void *value);
void fill(const void *value);
/**
* Copy the values from the source buffer to all elements in the virtual array.
*/
void set_all(const void *src);
GVMutableArrayImpl *get_implementation() const;
private:
GVMutableArrayImpl *get_impl() const;
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name #GVArray_GSpan and #GVMutableArray_GSpan.
* \{ */
/* A generic version of VArray_Span. */
class GVArray_GSpan : public GSpan {
private:
GVArray varray_;
void *owned_data_ = nullptr;
public:
GVArray_GSpan(GVArray varray);
~GVArray_GSpan();
};
/* A generic version of VMutableArray_Span. */
class GVMutableArray_GSpan : public GMutableSpan {
private:
GVMutableArray varray_;
void *owned_data_ = nullptr;
bool save_has_been_called_ = false;
bool show_not_saved_warning_ = true;
public:
GVMutableArray_GSpan(GVMutableArray varray, bool copy_values_to_span = true);
~GVMutableArray_GSpan();
void save();
void disable_not_applied_warning();
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name Conversions between generic and typed virtual arrays.
* \{ */
/* Used to convert a typed virtual array into a generic one. */
template<typename T> class GVArrayImpl_For_VArray : public GVArrayImpl {
protected:
VArray<T> varray_;
public:
GVArrayImpl_For_VArray(VArray<T> varray)
: GVArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray))
{
}
protected:
void get(const int64_t index, void *r_value) const override
{
*(T *)r_value = varray_[index];
}
void get_to_uninitialized(const int64_t index, void *r_value) const override
{
new (r_value) T(varray_[index]);
}
bool is_span() const override
{
return varray_.is_span();
}
GSpan get_internal_span() const override
{
return GSpan(varray_.get_internal_span());
}
bool is_single() const override
{
return varray_.is_single();
}
void get_internal_single(void *r_value) const override
{
*(T *)r_value = varray_.get_internal_single();
}
void materialize(const IndexMask mask, void *dst) const override
{
varray_.materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
void materialize_to_uninitialized(const IndexMask mask, void *dst) const override
{
varray_.materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
void materialize_compressed(const IndexMask mask, void *dst) const override
{
varray_.materialize_compressed(mask, MutableSpan((T *)dst, mask.size()));
}
void materialize_compressed_to_uninitialized(const IndexMask mask, void *dst) const override
{
varray_.materialize_compressed_to_uninitialized(mask, MutableSpan((T *)dst, mask.size()));
}
bool try_assign_VArray(void *varray) const override
{
*(VArray<T> *)varray = varray_;
return true;
}
bool may_have_ownership() const override
{
return varray_.may_have_ownership();
}
};
/* Used to convert any generic virtual array into a typed one. */
template<typename T> class VArrayImpl_For_GVArray : public VArrayImpl<T> {
protected:
GVArray varray_;
public:
VArrayImpl_For_GVArray(GVArray varray) : VArrayImpl<T>(varray.size()), varray_(std::move(varray))
{
BLI_assert(varray_);
BLI_assert(varray_.type().template is<T>());
}
protected:
T get(const int64_t index) const override
{
T value;
varray_.get(index, &value);
return value;
}
bool is_span() const override
{
return varray_.is_span();
}
Span<T> get_internal_span() const override
{
return varray_.get_internal_span().template typed<T>();
}
bool is_single() const override
{
return varray_.is_single();
}
T get_internal_single() const override
{
T value;
varray_.get_internal_single(&value);
return value;
}
bool try_assign_GVArray(GVArray &varray) const override
{
varray = varray_;
return true;
}
bool may_have_ownership() const override
{
return varray_.may_have_ownership();
}
void materialize(IndexMask mask, MutableSpan<T> r_span) const override
{
varray_.materialize(mask, r_span.data());
}
void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const override
{
varray_.materialize_to_uninitialized(mask, r_span.data());
}
void materialize_compressed(IndexMask mask, MutableSpan<T> r_span) const override
{
varray_.materialize_compressed(mask, r_span.data());
}
void materialize_compressed_to_uninitialized(IndexMask mask,
MutableSpan<T> r_span) const override
{
varray_.materialize_compressed_to_uninitialized(mask, r_span.data());
}
};
/* Used to convert any typed virtual mutable array into a generic one. */
template<typename T> class GVMutableArrayImpl_For_VMutableArray : public GVMutableArrayImpl {
protected:
VMutableArray<T> varray_;
public:
GVMutableArrayImpl_For_VMutableArray(VMutableArray<T> varray)
: GVMutableArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray))
{
}
protected:
void get(const int64_t index, void *r_value) const override
{
*(T *)r_value = varray_[index];
}
void get_to_uninitialized(const int64_t index, void *r_value) const override
{
new (r_value) T(varray_[index]);
}
bool is_span() const override
{
return varray_.is_span();
}
GSpan get_internal_span() const override
{
Span<T> span = varray_.get_internal_span();
return span;
}
bool is_single() const override
{
return varray_.is_single();
}
void get_internal_single(void *r_value) const override
{
*(T *)r_value = varray_.get_internal_single();
}
void set_by_copy(const int64_t index, const void *value) override
{
const T &value_ = *(const T *)value;
varray_.set(index, value_);
}
void set_by_relocate(const int64_t index, void *value) override
{
T &value_ = *(T *)value;
varray_.set(index, std::move(value_));
value_.~T();
}
void set_by_move(const int64_t index, void *value) override
{
T &value_ = *(T *)value;
varray_.set(index, std::move(value_));
}
void set_all(const void *src) override
{
varray_.set_all(Span((T *)src, size_));
}
void materialize(const IndexMask mask, void *dst) const override
{
varray_.materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
void materialize_to_uninitialized(const IndexMask mask, void *dst) const override
{
varray_.materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
void materialize_compressed(const IndexMask mask, void *dst) const override
{
varray_.materialize_compressed(mask, MutableSpan((T *)dst, mask.size()));
}
void materialize_compressed_to_uninitialized(const IndexMask mask, void *dst) const override
{
varray_.materialize_compressed_to_uninitialized(mask, MutableSpan((T *)dst, mask.size()));
}
bool try_assign_VArray(void *varray) const override
{
*(VArray<T> *)varray = varray_;
return true;
}
bool try_assign_VMutableArray(void *varray) const override
{
*(VMutableArray<T> *)varray = varray_;
return true;
}
bool may_have_ownership() const override
{
return varray_.may_have_ownership();
}
};
/* Used to convert an generic mutable virtual array into a typed one. */
template<typename T> class VMutableArrayImpl_For_GVMutableArray : public VMutableArrayImpl<T> {
protected:
GVMutableArray varray_;
public:
VMutableArrayImpl_For_GVMutableArray(GVMutableArray varray)
: VMutableArrayImpl<T>(varray.size()), varray_(varray)
{
BLI_assert(varray_);
BLI_assert(varray_.type().template is<T>());
}
private:
T get(const int64_t index) const override
{
T value;
varray_.get(index, &value);
return value;
}
void set(const int64_t index, T value) override
{
varray_.set_by_relocate(index, &value);
}
bool is_span() const override
{
return varray_.is_span();
}
Span<T> get_internal_span() const override
{
return varray_.get_internal_span().template typed<T>();
}
bool is_single() const override
{
return varray_.is_single();
}
T get_internal_single() const override
{
T value;
varray_.get_internal_single(&value);
return value;
}
bool try_assign_GVArray(GVArray &varray) const override
{
varray = varray_;
return true;
}
bool try_assign_GVMutableArray(GVMutableArray &varray) const override
{
varray = varray_;
return true;
}
bool may_have_ownership() const override
{
return varray_.may_have_ownership();
}
void materialize(IndexMask mask, MutableSpan<T> r_span) const override
{
varray_.materialize(mask, r_span.data());
}
void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const override
{
varray_.materialize_to_uninitialized(mask, r_span.data());
}
void materialize_compressed(IndexMask mask, MutableSpan<T> r_span) const override
{
varray_.materialize_compressed(mask, r_span.data());
}
void materialize_compressed_to_uninitialized(IndexMask mask,
MutableSpan<T> r_span) const override
{
varray_.materialize_compressed_to_uninitialized(mask, r_span.data());
}
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name #GVArrayImpl_For_GSpan.
* \{ */
class GVArrayImpl_For_GSpan : public GVMutableArrayImpl {
protected:
void *data_ = nullptr;
const int64_t element_size_;
public:
GVArrayImpl_For_GSpan(const GMutableSpan span)
: GVMutableArrayImpl(span.type(), span.size()),
data_(span.data()),
element_size_(span.type().size())
{
}
protected:
GVArrayImpl_For_GSpan(const CPPType &type, int64_t size)
: GVMutableArrayImpl(type, size), element_size_(type.size())
{
}
public:
void get(int64_t index, void *r_value) const override;
void get_to_uninitialized(int64_t index, void *r_value) const override;
void set_by_copy(int64_t index, const void *value) override;
void set_by_move(int64_t index, void *value) override;
void set_by_relocate(int64_t index, void *value) override;
bool is_span() const override;
GSpan get_internal_span() const override;
virtual void materialize(const IndexMask mask, void *dst) const override;
virtual void materialize_to_uninitialized(const IndexMask mask, void *dst) const override;
virtual void materialize_compressed(const IndexMask mask, void *dst) const override;
virtual void materialize_compressed_to_uninitialized(const IndexMask mask,
void *dst) const override;
};
class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
public:
using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan;
private:
bool may_have_ownership() const override
{
return false;
}
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name #GVArrayImpl_For_SingleValueRef.
* \{ */
class GVArrayImpl_For_SingleValueRef : public GVArrayImpl {
protected:
const void *value_ = nullptr;
public:
GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
: GVArrayImpl(type, size), value_(value)
{
}
protected:
GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArrayImpl(type, size)
{
}
void get(const int64_t index, void *r_value) const override;
void get_to_uninitialized(const int64_t index, void *r_value) const override;
bool is_span() const override;
GSpan get_internal_span() const override;
bool is_single() const override;
void get_internal_single(void *r_value) const override;
void materialize(const IndexMask mask, void *dst) const override;
void materialize_to_uninitialized(const IndexMask mask, void *dst) const override;
void materialize_compressed(const IndexMask mask, void *dst) const override;
void materialize_compressed_to_uninitialized(const IndexMask mask, void *dst) const override;
};
class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_SingleValueRef {
public:
using GVArrayImpl_For_SingleValueRef::GVArrayImpl_For_SingleValueRef;
private:
bool may_have_ownership() const override
{
return false;
}
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name Inline methods for #GVArrayImpl.
* \{ */
inline GVArrayImpl::GVArrayImpl(const CPPType &type, const int64_t size)
: type_(&type), size_(size)
{
BLI_assert(size_ >= 0);
}
inline const CPPType &GVArrayImpl::type() const
{
return *type_;
}
inline int64_t GVArrayImpl::size() const
{
return size_;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Inline methods for #GVMutableArrayImpl.
* \{ */
inline void GVMutableArray::set_by_copy(const int64_t index, const void *value)
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
this->get_impl()->set_by_copy(index, value);
}
inline void GVMutableArray::set_by_move(const int64_t index, void *value)
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
this->get_impl()->set_by_move(index, value);
}
inline void GVMutableArray::set_by_relocate(const int64_t index, void *value)
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
this->get_impl()->set_by_relocate(index, value);
}
template<typename T>
inline bool GVMutableArray::try_assign_VMutableArray(VMutableArray<T> &varray) const
{
BLI_assert(impl_->type().is<T>());
return this->get_impl()->try_assign_VMutableArray(&varray);
}
inline GVMutableArrayImpl *GVMutableArray::get_impl() const
{
return (GVMutableArrayImpl *)impl_;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Inline methods for #GVArrayCommon.
* \{ */
template<typename ImplT, typename... Args> inline void GVArrayCommon::emplace(Args &&...args)
{
static_assert(std::is_base_of_v<GVArrayImpl, ImplT>);
if constexpr (std::is_copy_constructible_v<ImplT> && Storage::template is_inline_v<ImplT>) {
impl_ = &storage_.template emplace<ImplT>(std::forward<Args>(args)...);
}
else {
std::shared_ptr<const GVArrayImpl> ptr = std::make_shared<ImplT>(std::forward<Args>(args)...);
impl_ = &*ptr;
storage_ = std::move(ptr);
}
}
/* Copies the value at the given index into the provided storage. The `r_value` pointer is
* expected to point to initialized memory. */
inline void GVArrayCommon::get(const int64_t index, void *r_value) const
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
impl_->get(index, r_value);
}
template<typename T> inline T GVArrayCommon::get(const int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
BLI_assert(this->type().is<T>());
T value{};
impl_->get(index, &value);
return value;
}
/* Same as `get`, but `r_value` is expected to point to uninitialized memory. */
inline void GVArrayCommon::get_to_uninitialized(const int64_t index, void *r_value) const
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
impl_->get_to_uninitialized(index, r_value);
}
template<typename T> inline bool GVArrayCommon::try_assign_VArray(VArray<T> &varray) const
{
BLI_assert(impl_->type().is<T>());
return impl_->try_assign_VArray(&varray);
}
inline const CPPType &GVArrayCommon::type() const
{
return impl_->type();
}
inline GVArrayCommon::operator bool() const
{
return impl_ != nullptr;
}
inline int64_t GVArrayCommon::size() const
{
if (impl_ == nullptr) {
return 0;
}
return impl_->size();
}
inline bool GVArrayCommon::is_empty() const
{
return this->size() == 0;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Inline methods for #GVArray.
* \{ */
inline GVArray::GVArray(varray_tag::span /* tag */, const GSpan span)
{
/* Use const-cast because the underlying virtual array implementation is shared between const
* and non const data. */
GMutableSpan mutable_span{span.type(), const_cast<void *>(span.data()), span.size()};
this->emplace<GVArrayImpl_For_GSpan_final>(mutable_span);
}
inline GVArray::GVArray(varray_tag::single_ref /* tag */,
const CPPType &type,
const int64_t size,
const void *value)
{
this->emplace<GVArrayImpl_For_SingleValueRef_final>(type, size, value);
}
namespace detail {
template<typename StorageT> constexpr GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get()
{
static_assert(std::is_base_of_v<GVArrayImpl, StorageT> ||
is_same_any_v<StorageT, const GVArrayImpl *, std::shared_ptr<const GVArrayImpl>>);
if constexpr (std::is_base_of_v<GVArrayImpl, StorageT>) {
return {[](const void *buffer) {
return static_cast<const GVArrayImpl *>((const StorageT *)buffer);
}};
}
else if constexpr (std::is_same_v<StorageT, const GVArrayImpl *>) {
return {[](const void *buffer) { return *(const StorageT *)buffer; }};
}
else if constexpr (std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>) {
return {[](const void *buffer) { return ((const StorageT *)buffer)->get(); }};
}
else {
BLI_assert_unreachable();
return {};
}
}
} // namespace detail
template<typename ImplT, typename... Args> inline GVArray GVArray::For(Args &&...args)
{
static_assert(std::is_base_of_v<GVArrayImpl, ImplT>);
GVArray varray;
varray.template emplace<ImplT>(std::forward<Args>(args)...);
return varray;
}
template<typename T> inline GVArray::GVArray(const VArray<T> &varray)
{
if (!varray) {
return;
}
if (varray.try_assign_GVArray(*this)) {
return;
}
/* Need to check this before the span/single special cases, because otherwise we might loose
* ownership to the referenced data when #varray goes out of scope. */
if (varray.may_have_ownership()) {
*this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
}
else if (varray.is_single()) {
T value = varray.get_internal_single();
*this = GVArray::ForSingle(CPPType::get<T>(), varray.size(), &value);
}
else if (varray.is_span()) {
Span<T> data = varray.get_internal_span();
*this = GVArray::ForSpan(data);
}
else {
*this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
}
}
template<typename T> inline VArray<T> GVArray::typed() const
{
if (!*this) {
return {};
}
BLI_assert(impl_->type().is<T>());
VArray<T> varray;
if (this->try_assign_VArray(varray)) {
return varray;
}
if (this->may_have_ownership()) {
return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
}
if (this->is_single()) {
T value;
this->get_internal_single(&value);
return VArray<T>::ForSingle(value, this->size());
}
if (this->is_span()) {
const Span<T> span = this->get_internal_span().typed<T>();
return VArray<T>::ForSpan(span);
}
return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Inline methods for #GVMutableArray.
* \{ */
template<typename ImplT, typename... Args>
inline GVMutableArray GVMutableArray::For(Args &&...args)
{
static_assert(std::is_base_of_v<GVMutableArrayImpl, ImplT>);
GVMutableArray varray;
varray.emplace<ImplT>(std::forward<Args>(args)...);
return varray;
}
template<typename T> inline GVMutableArray::GVMutableArray(const VMutableArray<T> &varray)
{
if (!varray) {
return;
}
if (varray.try_assign_GVMutableArray(*this)) {
return;
}
if (varray.may_have_ownership()) {
*this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray);
}
else if (varray.is_span()) {
MutableSpan<T> data = varray.get_internal_span();
*this = GVMutableArray::ForSpan(data);
}
else {
*this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray);
}
}
template<typename T> inline VMutableArray<T> GVMutableArray::typed() const
{
if (!*this) {
return {};
}
BLI_assert(this->type().is<T>());
VMutableArray<T> varray;
if (this->try_assign_VMutableArray(varray)) {
return varray;
}
if (this->may_have_ownership()) {
return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this);
}
if (this->is_span()) {
const MutableSpan<T> span = this->get_internal_span().typed<T>();
return VMutableArray<T>::ForSpan(span);
}
return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this);
}
/** \} */
} // namespace blender