Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/functions/FN_generic_virtual_array.hh')
-rw-r--r--source/blender/functions/FN_generic_virtual_array.hh681
1 files changed, 636 insertions, 45 deletions
diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh
index c6230730a8d..00f6cacd2e1 100644
--- a/source/blender/functions/FN_generic_virtual_array.hh
+++ b/source/blender/functions/FN_generic_virtual_array.hh
@@ -23,12 +23,17 @@
* the data type is only known at runtime.
*/
+#include <optional>
+
#include "BLI_virtual_array.hh"
#include "FN_generic_span.hh"
namespace blender::fn {
+template<typename T> class GVArray_Typed;
+template<typename T> class GVMutableArray_Typed;
+
/* A generically typed version of `VArray<T>`. */
class GVArray {
protected:
@@ -86,13 +91,13 @@ class GVArray {
/* Returns the internally used span of the virtual array. This invokes undefined behavior is the
* virtual array is not stored as a span internally. */
- GSpan get_span() const
+ GSpan get_internal_span() const
{
BLI_assert(this->is_span());
if (size_ == 0) {
return GSpan(*type_);
}
- return this->get_span_impl();
+ return this->get_internal_span_impl();
}
/* Returns true when the virtual array returns the same value for every index. */
@@ -107,57 +112,133 @@ class GVArray {
/* 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_single(void *r_value) const
+ void get_internal_single(void *r_value) const
{
BLI_assert(this->is_single());
if (size_ == 1) {
this->get(0, r_value);
}
- this->get_single_impl(r_value);
+ this->get_internal_single_impl(r_value);
}
- /* Same as `get_single`, but `r_value` points to initialized memory. */
+ /* Same as `get_internal_single`, but `r_value` points to initialized memory. */
void get_single_to_uninitialized(void *r_value) const
{
type_->construct_default(r_value);
- this->get_single(r_value);
+ this->get_internal_single(r_value);
}
void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
+ template<typename T> const VArray<T> *try_get_internal_varray() const
+ {
+ BLI_assert(type_->is<T>());
+ return (const VArray<T> *)this->try_get_internal_varray_impl();
+ }
+
+ /* Create a typed virtual array for this generic virtual array. */
+ template<typename T> GVArray_Typed<T> typed() const
+ {
+ return GVArray_Typed<T>(*this);
+ }
+
protected:
virtual void get_impl(const int64_t index, void *r_value) const;
virtual void get_to_uninitialized_impl(const int64_t index, void *r_value) const = 0;
virtual bool is_span_impl() const;
- virtual GSpan get_span_impl() const;
+ virtual GSpan get_internal_span_impl() const;
virtual bool is_single_impl() const;
- virtual void get_single_impl(void *UNUSED(r_value)) const;
+ virtual void get_internal_single_impl(void *UNUSED(r_value)) const;
+
+ virtual const void *try_get_internal_varray_impl() const;
+};
+
+/* Similar to GVArray, but supports changing the elements in the virtual array. */
+class GVMutableArray : public GVArray {
+ public:
+ GVMutableArray(const CPPType &type, const int64_t size) : GVArray(type, size)
+ {
+ }
+
+ void set_by_copy(const int64_t index, const void *value)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ this->set_by_copy_impl(index, value);
+ }
+
+ void set_by_move(const int64_t index, void *value)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ this->set_by_move_impl(index, value);
+ }
+
+ void set_by_relocate(const int64_t index, void *value)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ this->set_by_relocate_impl(index, value);
+ }
+
+ GMutableSpan get_internal_span()
+ {
+ BLI_assert(this->is_span());
+ GSpan span = static_cast<const GVArray *>(this)->get_internal_span();
+ return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size());
+ }
+
+ template<typename T> VMutableArray<T> *try_get_internal_mutable_varray()
+ {
+ BLI_assert(type_->is<T>());
+ return (VMutableArray<T> *)this->try_get_internal_mutable_varray_impl();
+ }
+
+ /* Create a typed virtual array for this generic virtual array. */
+ template<typename T> GVMutableArray_Typed<T> typed()
+ {
+ return GVMutableArray_Typed<T>(*this);
+ }
+
+ void fill(const void *value);
+
+ protected:
+ virtual void set_by_copy_impl(const int64_t index, const void *value);
+ virtual void set_by_relocate_impl(const int64_t index, void *value);
+ virtual void set_by_move_impl(const int64_t index, void *value) = 0;
+
+ virtual void *try_get_internal_mutable_varray_impl();
};
-class GVArrayForGSpan : public GVArray {
+class GVArray_For_GSpan : public GVArray {
protected:
- const void *data_;
+ const void *data_ = nullptr;
const int64_t element_size_;
public:
- GVArrayForGSpan(const GSpan span)
+ GVArray_For_GSpan(const GSpan span)
: GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size())
{
}
protected:
+ GVArray_For_GSpan(const CPPType &type, const int64_t size)
+ : GVArray(type, size), element_size_(type.size())
+ {
+ }
+
void get_impl(const int64_t index, void *r_value) const override;
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
bool is_span_impl() const override;
- GSpan get_span_impl() const override;
+ GSpan get_internal_span_impl() const override;
};
-class GVArrayForEmpty : public GVArray {
+class GVArray_For_Empty : public GVArray {
public:
- GVArrayForEmpty(const CPPType &type) : GVArray(type, 0)
+ GVArray_For_Empty(const CPPType &type) : GVArray(type, 0)
{
}
@@ -168,108 +249,618 @@ class GVArrayForEmpty : public GVArray {
}
};
-class GVArrayForSingleValueRef : public GVArray {
- private:
- const void *value_;
+class GVMutableArray_For_GMutableSpan : public GVMutableArray {
+ protected:
+ void *data_ = nullptr;
+ const int64_t element_size_;
+
+ public:
+ GVMutableArray_For_GMutableSpan(const GMutableSpan span)
+ : GVMutableArray(span.type(), span.size()),
+ data_(span.data()),
+ element_size_(span.type().size())
+ {
+ }
+
+ protected:
+ GVMutableArray_For_GMutableSpan(const CPPType &type, const int64_t size)
+ : GVMutableArray(type, size), element_size_(type.size())
+ {
+ }
+
+ void get_impl(const int64_t index, void *r_value) const override;
+ void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
+
+ void set_by_copy_impl(const int64_t index, const void *value) override;
+ void set_by_move_impl(const int64_t index, void *value) override;
+ void set_by_relocate_impl(const int64_t index, void *value) override;
+
+ bool is_span_impl() const override;
+ GSpan get_internal_span_impl() const override;
+};
+
+/* Generic virtual array where each element has the same value. The value is not owned. */
+class GVArray_For_SingleValueRef : public GVArray {
+ protected:
+ const void *value_ = nullptr;
public:
- GVArrayForSingleValueRef(const CPPType &type, const int64_t size, const void *value)
+ GVArray_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
: GVArray(type, size), value_(value)
{
}
protected:
+ GVArray_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArray(type, size)
+ {
+ }
+
void get_impl(const int64_t index, void *r_value) const override;
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
bool is_span_impl() const override;
- GSpan get_span_impl() const override;
+ GSpan get_internal_span_impl() const override;
bool is_single_impl() const override;
- void get_single_impl(void *r_value) const override;
+ void get_internal_single_impl(void *r_value) const override;
};
-template<typename T> class GVArrayForVArray : public GVArray {
- private:
- const VArray<T> &array_;
+/* Same as GVArray_For_SingleValueRef, but the value is owned. */
+class GVArray_For_SingleValue : public GVArray_For_SingleValueRef {
+ public:
+ GVArray_For_SingleValue(const CPPType &type, const int64_t size, const void *value);
+ ~GVArray_For_SingleValue();
+};
+
+/* Used to convert a typed virtual array into a generic one. */
+template<typename T> class GVArray_For_VArray : public GVArray {
+ protected:
+ const VArray<T> *varray_ = nullptr;
public:
- GVArrayForVArray(const VArray<T> &array)
- : GVArray(CPPType::get<T>(), array.size()), array_(array)
+ GVArray_For_VArray(const VArray<T> &varray)
+ : GVArray(CPPType::get<T>(), varray.size()), varray_(&varray)
{
}
protected:
+ GVArray_For_VArray(const int64_t size) : GVArray(CPPType::get<T>(), size)
+ {
+ }
+
void get_impl(const int64_t index, void *r_value) const override
{
- *(T *)r_value = array_.get(index);
+ *(T *)r_value = varray_->get(index);
}
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
{
- new (r_value) T(array_.get(index));
+ new (r_value) T(varray_->get(index));
}
bool is_span_impl() const override
{
- return array_.is_span();
+ return varray_->is_span();
}
- GSpan get_span_impl() const override
+ GSpan get_internal_span_impl() const override
{
- return GSpan(array_.get_span());
+ return GSpan(varray_->get_internal_span());
}
bool is_single_impl() const override
{
- return array_.is_single();
+ return varray_->is_single();
+ }
+
+ void get_internal_single_impl(void *r_value) const override
+ {
+ *(T *)r_value = varray_->get_internal_single();
}
- void get_single_impl(void *r_value) const override
+ const void *try_get_internal_varray_impl() const override
{
- *(T *)r_value = array_.get_single();
+ return varray_;
}
};
-template<typename T> class VArrayForGVArray : public VArray<T> {
- private:
- const GVArray &array_;
+/* Used to convert any generic virtual array into a typed one. */
+template<typename T> class VArray_For_GVArray : public VArray<T> {
+ protected:
+ const GVArray *varray_ = nullptr;
public:
- VArrayForGVArray(const GVArray &array) : VArray<T>(array.size()), array_(array)
+ VArray_For_GVArray(const GVArray &varray) : VArray<T>(varray.size()), varray_(&varray)
{
- BLI_assert(array_.type().template is<T>());
+ BLI_assert(varray_->type().template is<T>());
}
protected:
+ VArray_For_GVArray(const int64_t size) : VArray<T>(size)
+ {
+ }
+
T get_impl(const int64_t index) const override
{
T value;
- array_.get(index, &value);
+ varray_->get(index, &value);
return value;
}
bool is_span_impl() const override
{
- return array_.is_span();
+ return varray_->is_span();
}
- Span<T> get_span_impl() const override
+ Span<T> get_internal_span_impl() const override
{
- return array_.get_span().template typed<T>();
+ return varray_->get_internal_span().template typed<T>();
}
bool is_single_impl() const override
{
- return array_.is_single();
+ return varray_->is_single();
+ }
+
+ T get_internal_single_impl() const override
+ {
+ T value;
+ varray_->get_internal_single(&value);
+ return value;
+ }
+};
+
+/* Used to convert an generic mutable virtual array into a typed one. */
+template<typename T> class VMutableArray_For_GVMutableArray : public VMutableArray<T> {
+ protected:
+ GVMutableArray *varray_ = nullptr;
+
+ public:
+ VMutableArray_For_GVMutableArray(GVMutableArray &varray)
+ : VMutableArray<T>(varray.size()), varray_(&varray)
+ {
+ BLI_assert(varray.type().template is<T>());
+ }
+
+ VMutableArray_For_GVMutableArray(const int64_t size) : VMutableArray<T>(size)
+ {
}
- T get_single_impl() const override
+ private:
+ T get_impl(const int64_t index) const override
{
T value;
- array_.get_single(&value);
+ varray_->get(index, &value);
return value;
}
+
+ void set_impl(const int64_t index, T value) override
+ {
+ varray_->set_by_relocate(index, &value);
+ }
+
+ bool is_span_impl() const override
+ {
+ return varray_->is_span();
+ }
+
+ Span<T> get_internal_span_impl() const override
+ {
+ return varray_->get_internal_span().template typed<T>();
+ }
+
+ bool is_single_impl() const override
+ {
+ return varray_->is_single();
+ }
+
+ T get_internal_single_impl() const override
+ {
+ T value;
+ varray_->get_internal_single(&value);
+ return value;
+ }
+};
+
+/* Used to convert any typed virtual mutable array into a generic one. */
+template<typename T> class GVMutableArray_For_VMutableArray : public GVMutableArray {
+ protected:
+ VMutableArray<T> *varray_ = nullptr;
+
+ public:
+ GVMutableArray_For_VMutableArray(VMutableArray<T> &varray)
+ : GVMutableArray(CPPType::get<T>(), varray.size()), varray_(&varray)
+ {
+ }
+
+ protected:
+ GVMutableArray_For_VMutableArray(const int64_t size) : GVMutableArray(CPPType::get<T>(), size)
+ {
+ }
+
+ void get_impl(const int64_t index, void *r_value) const override
+ {
+ *(T *)r_value = varray_->get(index);
+ }
+
+ void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ {
+ new (r_value) T(varray_->get(index));
+ }
+
+ bool is_span_impl() const override
+ {
+ return varray_->is_span();
+ }
+
+ GSpan get_internal_span_impl() const override
+ {
+ Span<T> span = varray_->get_internal_span();
+ return span;
+ }
+
+ bool is_single_impl() const override
+ {
+ return varray_->is_single();
+ }
+
+ void get_internal_single_impl(void *r_value) const override
+ {
+ *(T *)r_value = varray_->get_internal_single();
+ }
+
+ void set_by_copy_impl(const int64_t index, const void *value) override
+ {
+ const T &value_ = *(const T *)value;
+ varray_->set(index, value_);
+ }
+
+ void set_by_relocate_impl(const int64_t index, void *value) override
+ {
+ T &value_ = *(T *)value;
+ varray_->set(index, std::move(value_));
+ value_.~T();
+ }
+
+ void set_by_move_impl(const int64_t index, void *value) override
+ {
+ T &value_ = *(T *)value;
+ varray_->set(index, std::move(value_));
+ }
+
+ const void *try_get_internal_varray_impl() const override
+ {
+ return (const VArray<T> *)varray_;
+ }
+
+ void *try_get_internal_mutable_varray_impl() override
+ {
+ return varray_;
+ }
+};
+
+/* A generic version of VArray_Span. */
+class GVArray_GSpan : public GSpan {
+ private:
+ const GVArray &varray_;
+ void *owned_data_ = nullptr;
+
+ public:
+ GVArray_GSpan(const 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();
+};
+
+/* Similar to GVArray_GSpan, but the resulting span is typed. */
+template<typename T> class GVArray_Span : public Span<T> {
+ private:
+ GVArray_GSpan varray_gspan_;
+
+ public:
+ GVArray_Span(const GVArray &varray) : varray_gspan_(varray)
+ {
+ BLI_assert(varray.type().is<T>());
+ this->data_ = (const T *)varray_gspan_.data();
+ this->size_ = varray_gspan_.size();
+ }
+};
+
+template<typename T> class GVArray_For_OwnedVArray : public GVArray_For_VArray<T> {
+ private:
+ std::unique_ptr<VArray<T>> owned_varray_;
+
+ public:
+ /* Takes ownership of varray and passes a reference to the base class. */
+ GVArray_For_OwnedVArray(std::unique_ptr<VArray<T>> varray)
+ : GVArray_For_VArray<T>(*varray), owned_varray_(std::move(varray))
+ {
+ }
+};
+
+template<typename T> class VArray_For_OwnedGVArray : public VArray_For_GVArray<T> {
+ private:
+ std::unique_ptr<VArray<T>> owned_varray_;
+
+ public:
+ /* Takes ownership of varray and passes a reference to the base class. */
+ VArray_For_OwnedGVArray(std::unique_ptr<GVArray> varray)
+ : VArray_For_GVArray<T>(*varray), owned_varray_(std::move(varray))
+ {
+ }
+};
+
+template<typename T>
+class GVMutableArray_For_OwnedVMutableArray : public GVMutableArray_For_VMutableArray<T> {
+ private:
+ std::unique_ptr<VMutableArray<T>> owned_varray_;
+
+ public:
+ /* Takes ownership of varray and passes a reference to the base class. */
+ GVMutableArray_For_OwnedVMutableArray(std::unique_ptr<VMutableArray<T>> varray)
+ : GVMutableArray_For_VMutableArray<T>(*varray), owned_varray_(std::move(varray))
+ {
+ }
+};
+
+template<typename T>
+class VMutableArray_For_OwnedGVMutableArray : public VMutableArray_For_GVMutableArray<T> {
+ private:
+ std::unique_ptr<GVMutableArray> owned_varray_;
+
+ public:
+ /* Takes ownership of varray and passes a reference to the base class. */
+ VMutableArray_For_OwnedGVMutableArray(std::unique_ptr<GVMutableArray> varray)
+ : VMutableArray_For_GVMutableArray<T>(*varray), owned_varray_(std::move(varray))
+ {
+ }
+};
+
+/* Utility to embed a typed virtual array into a generic one. This avoids one allocation and give
+ * the compiler more opportunity to optimize the generic virtual array. */
+template<typename T, typename VArrayT>
+class GVArray_For_EmbeddedVArray : public GVArray_For_VArray<T> {
+ private:
+ VArrayT embedded_varray_;
+
+ public:
+ template<typename... Args>
+ GVArray_For_EmbeddedVArray(const int64_t size, Args &&... args)
+ : GVArray_For_VArray<T>(size), embedded_varray_(std::forward<Args>(args)...)
+ {
+ this->varray_ = &embedded_varray_;
+ }
+};
+
+/* Same as GVArray_For_EmbeddedVArray, but for mutable virtual arrays. */
+template<typename T, typename VMutableArrayT>
+class GVMutableArray_For_EmbeddedVMutableArray : public GVMutableArray_For_VMutableArray<T> {
+ private:
+ VMutableArrayT embedded_varray_;
+
+ public:
+ template<typename... Args>
+ GVMutableArray_For_EmbeddedVMutableArray(const int64_t size, Args &&... args)
+ : GVMutableArray_For_VMutableArray<T>(size), embedded_varray_(std::forward<Args>(args)...)
+ {
+ this->varray_ = &embedded_varray_;
+ }
+};
+
+/* Same as VArray_For_ArrayContainer, but for a generic virtual array. */
+template<typename Container, typename T = typename Container::value_type>
+class GVArray_For_ArrayContainer
+ : public GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>> {
+ public:
+ GVArray_For_ArrayContainer(Container container)
+ : GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>>(
+ container.size(), std::move(container))
+ {
+ }
+};
+
+/* Same as VArray_For_DerivedSpan, but for a generic virtual array. */
+template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
+class GVArray_For_DerivedSpan
+ : public GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>> {
+ public:
+ GVArray_For_DerivedSpan(const Span<StructT> data)
+ : GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>>(
+ data.size(), data)
+ {
+ }
+};
+
+/* Same as VMutableArray_For_DerivedSpan, but for a generic virtual array. */
+template<typename StructT,
+ typename ElemT,
+ ElemT (*GetFunc)(const StructT &),
+ void (*SetFunc)(StructT &, ElemT)>
+class GVMutableArray_For_DerivedSpan
+ : public GVMutableArray_For_EmbeddedVMutableArray<
+ ElemT,
+ VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>> {
+ public:
+ GVMutableArray_For_DerivedSpan(const MutableSpan<StructT> data)
+ : GVMutableArray_For_EmbeddedVMutableArray<
+ ElemT,
+ VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(data.size(), data)
+ {
+ }
+};
+
+/* Same as VArray_For_Span, but for a generic virtual array. */
+template<typename T>
+class GVArray_For_Span : public GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>> {
+ public:
+ GVArray_For_Span(const Span<T> data)
+ : GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>>(data.size(), data)
+ {
+ }
+};
+
+/* Same as VMutableArray_For_MutableSpan, but for a generic virtual array. */
+template<typename T>
+class GVMutableArray_For_MutableSpan
+ : public GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>> {
+ public:
+ GVMutableArray_For_MutableSpan(const MutableSpan<T> data)
+ : GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>>(data.size(),
+ data)
+ {
+ }
+};
+
+/**
+ * Utility class to create the "best" typed virtual array for a given generic virtual array.
+ * In most cases we don't just want to use VArray_For_GVArray, because it adds an additional
+ * indirection on element-access that can be avoided in many cases (e.g. when the virtual array is
+ * just a span or single value).
+ *
+ * This is not a virtual array itself, but is used to get a virtual array.
+ */
+template<typename T> class GVArray_Typed {
+ private:
+ const VArray<T> *varray_;
+ /* Of these optional virtual arrays, at most one is constructed at any time. */
+ std::optional<VArray_For_Span<T>> varray_span_;
+ std::optional<VArray_For_Single<T>> varray_single_;
+ std::optional<VArray_For_GVArray<T>> varray_any_;
+ std::unique_ptr<GVArray> owned_gvarray_;
+
+ public:
+ explicit GVArray_Typed(const GVArray &gvarray)
+ {
+ BLI_assert(gvarray.type().is<T>());
+ if (gvarray.is_span()) {
+ const GSpan span = gvarray.get_internal_span();
+ varray_span_.emplace(span.typed<T>());
+ varray_ = &*varray_span_;
+ }
+ else if (gvarray.is_single()) {
+ T single_value;
+ gvarray.get_internal_single(&single_value);
+ varray_single_.emplace(single_value, gvarray.size());
+ varray_ = &*varray_single_;
+ }
+ else if (const VArray<T> *internal_varray = gvarray.try_get_internal_varray<T>()) {
+ varray_ = internal_varray;
+ }
+ else {
+ varray_any_.emplace(gvarray);
+ varray_ = &*varray_any_;
+ }
+ }
+
+ /* Same as the constructor above, but also takes ownership of the passed in virtual array. */
+ explicit GVArray_Typed(std::unique_ptr<GVArray> gvarray) : GVArray_Typed(*gvarray)
+ {
+ owned_gvarray_ = std::move(gvarray);
+ }
+
+ const VArray<T> &operator*() const
+ {
+ return *varray_;
+ }
+
+ const VArray<T> *operator->() const
+ {
+ return varray_;
+ }
+
+ /* Support implicit cast to the typed virtual array for convenience when `varray->typed<T>()` is
+ * used within an expression. */
+ operator const VArray<T> &() const
+ {
+ return *varray_;
+ }
+
+ T operator[](const int64_t index) const
+ {
+ return varray_->get(index);
+ }
+
+ int64_t size() const
+ {
+ return varray_->size();
+ }
+
+ IndexRange index_range() const
+ {
+ return IndexRange(this->size());
+ }
+};
+
+/* Same as GVArray_Typed, but for mutable virtual arrays. */
+template<typename T> class GVMutableArray_Typed {
+ private:
+ VMutableArray<T> *varray_;
+ std::optional<VMutableArray_For_MutableSpan<T>> varray_span_;
+ std::optional<VMutableArray_For_GVMutableArray<T>> varray_any_;
+ std::unique_ptr<GVMutableArray> owned_gvarray_;
+
+ public:
+ explicit GVMutableArray_Typed(GVMutableArray &gvarray)
+ {
+ BLI_assert(gvarray.type().is<T>());
+ if (gvarray.is_span()) {
+ const GMutableSpan span = gvarray.get_internal_span();
+ varray_span_.emplace(span.typed<T>());
+ varray_ = &*varray_span_;
+ }
+ else if (VMutableArray<T> *internal_varray = gvarray.try_get_internal_mutable_varray<T>()) {
+ varray_ = internal_varray;
+ }
+ else {
+ varray_any_.emplace(gvarray);
+ varray_ = &*varray_any_;
+ }
+ }
+
+ explicit GVMutableArray_Typed(std::unique_ptr<GVMutableArray> gvarray)
+ : GVMutableArray_Typed(*gvarray)
+ {
+ owned_gvarray_ = std::move(gvarray);
+ }
+
+ VMutableArray<T> &operator*()
+ {
+ return *varray_;
+ }
+
+ VMutableArray<T> *operator->()
+ {
+ return varray_;
+ }
+
+ operator VMutableArray<T> &()
+ {
+ return *varray_;
+ }
+
+ T operator[](const int64_t index) const
+ {
+ return varray_->get(index);
+ }
+
+ int64_t size() const
+ {
+ return varray_->size();
+ }
};
} // namespace blender::fn