diff options
Diffstat (limited to 'source/blender/functions')
10 files changed, 888 insertions, 107 deletions
diff --git a/source/blender/functions/FN_generic_span.hh b/source/blender/functions/FN_generic_span.hh index 31b67dd3d70..ea2bd49fa09 100644 --- a/source/blender/functions/FN_generic_span.hh +++ b/source/blender/functions/FN_generic_span.hh @@ -30,7 +30,7 @@ namespace blender::fn { * A generic span. It behaves just like a blender::Span<T>, but the type is only known at run-time. */ class GSpan { - private: + protected: const CPPType *type_; const void *data_; int64_t size_; @@ -92,7 +92,7 @@ class GSpan { * known at run-time. */ class GMutableSpan { - private: + protected: const CPPType *type_; void *data_; int64_t size_; diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/functions/FN_generic_vector_array.hh index ae6eb8a614f..b02ed471875 100644 --- a/source/blender/functions/FN_generic_vector_array.hh +++ b/source/blender/functions/FN_generic_vector_array.hh @@ -123,7 +123,7 @@ template<typename T> class GVectorArray_TypedMutableRef { void extend(const int64_t index, const VArray<T> &values) { - GVArrayForVArray<T> array{values}; + GVArray_For_VArray<T> array{values}; this->extend(index, array); } @@ -134,12 +134,12 @@ template<typename T> class GVectorArray_TypedMutableRef { }; /* A generic virtual vector array implementation for a `GVectorArray`. */ -class GVVectorArrayForGVectorArray : public GVVectorArray { +class GVVectorArray_For_GVectorArray : public GVVectorArray { private: const GVectorArray &vector_array_; public: - GVVectorArrayForGVectorArray(const GVectorArray &vector_array) + GVVectorArray_For_GVectorArray(const GVectorArray &vector_array) : GVVectorArray(vector_array.type(), vector_array.size()), vector_array_(vector_array) { } 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 diff --git a/source/blender/functions/FN_generic_virtual_vector_array.hh b/source/blender/functions/FN_generic_virtual_vector_array.hh index ef3f53b5c25..4155a55a801 100644 --- a/source/blender/functions/FN_generic_virtual_vector_array.hh +++ b/source/blender/functions/FN_generic_virtual_vector_array.hh @@ -100,13 +100,13 @@ class GVVectorArray { } }; -class GVArrayForGVVectorArrayIndex : public GVArray { +class GVArray_For_GVVectorArrayIndex : public GVArray { private: const GVVectorArray &vector_array_; const int64_t index_; public: - GVArrayForGVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index) + GVArray_For_GVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index) : GVArray(vector_array.type(), vector_array.get_vector_size(index)), vector_array_(vector_array), index_(index) @@ -118,12 +118,12 @@ class GVArrayForGVVectorArrayIndex : public GVArray { void get_to_uninitialized_impl(const int64_t index_in_vector, void *r_value) const override; }; -class GVVectorArrayForSingleGVArray : public GVVectorArray { +class GVVectorArray_For_SingleGVArray : public GVVectorArray { private: const GVArray &array_; public: - GVVectorArrayForSingleGVArray(const GVArray &array, const int64_t size) + GVVectorArray_For_SingleGVArray(const GVArray &array, const int64_t size) : GVVectorArray(array.type(), size), array_(array) { } @@ -137,12 +137,12 @@ class GVVectorArrayForSingleGVArray : public GVVectorArray { bool is_single_vector_impl() const override; }; -class GVVectorArrayForSingleGSpan : public GVVectorArray { +class GVVectorArray_For_SingleGSpan : public GVVectorArray { private: const GSpan span_; public: - GVVectorArrayForSingleGSpan(const GSpan span, const int64_t size) + GVVectorArray_For_SingleGSpan(const GSpan span, const int64_t size) : GVVectorArray(span.type(), size), span_(span) { } @@ -156,12 +156,12 @@ class GVVectorArrayForSingleGSpan : public GVVectorArray { bool is_single_vector_impl() const override; }; -template<typename T> class VVectorArrayForGVVectorArray : public VVectorArray<T> { +template<typename T> class VVectorArray_For_GVVectorArray : public VVectorArray<T> { private: const GVVectorArray &vector_array_; public: - VVectorArrayForGVVectorArray(const GVVectorArray &vector_array) + VVectorArray_For_GVVectorArray(const GVVectorArray &vector_array) : VVectorArray<T>(vector_array.size()), vector_array_(vector_array) { } diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh index 72ebc0d9b94..3b15f0278f3 100644 --- a/source/blender/functions/FN_multi_function_params.hh +++ b/source/blender/functions/FN_multi_function_params.hh @@ -55,13 +55,13 @@ class MFParamsBuilder { template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "") { - this->add_readonly_single_input(scope_.construct<GVArrayForSingleValueRef>( + this->add_readonly_single_input(scope_.construct<GVArray_For_SingleValueRef>( __func__, CPPType::get<T>(), min_array_size_, value), expected_name); } void add_readonly_single_input(const GSpan span, StringRef expected_name = "") { - this->add_readonly_single_input(scope_.construct<GVArrayForGSpan>(__func__, span), + this->add_readonly_single_input(scope_.construct<GVArray_For_GSpan>(__func__, span), expected_name); } void add_readonly_single_input(const GVArray &ref, StringRef expected_name = "") @@ -74,7 +74,7 @@ class MFParamsBuilder { void add_readonly_vector_input(const GVectorArray &vector_array, StringRef expected_name = "") { this->add_readonly_vector_input( - scope_.construct<GVVectorArrayForGVectorArray>(__func__, vector_array), expected_name); + scope_.construct<GVVectorArray_For_GVectorArray>(__func__, vector_array), expected_name); } void add_readonly_vector_input(const GVVectorArray &ref, StringRef expected_name = "") { @@ -177,7 +177,7 @@ class MFParams { template<typename T> const VArray<T> &readonly_single_input(int param_index, StringRef name = "") { const GVArray &array = this->readonly_single_input(param_index, name); - return builder_->scope_.construct<VArrayForGVArray<T>>(__func__, array); + return builder_->scope_.construct<VArray_For_GVArray<T>>(__func__, array); } const GVArray &readonly_single_input(int param_index, StringRef name = "") { @@ -202,7 +202,7 @@ class MFParams { const VVectorArray<T> &readonly_vector_input(int param_index, StringRef name = "") { const GVVectorArray &vector_array = this->readonly_vector_input(param_index, name); - return builder_->scope_.construct<VVectorArrayForGVVectorArray<T>>(__func__, vector_array); + return builder_->scope_.construct<VVectorArray_For_GVVectorArray<T>>(__func__, vector_array); } const GVVectorArray &readonly_vector_input(int param_index, StringRef name = "") { diff --git a/source/blender/functions/intern/generic_vector_array.cc b/source/blender/functions/intern/generic_vector_array.cc index b3c5517cc43..3335b07e559 100644 --- a/source/blender/functions/intern/generic_vector_array.cc +++ b/source/blender/functions/intern/generic_vector_array.cc @@ -60,21 +60,21 @@ void GVectorArray::extend(const int64_t index, const GVArray &values) void GVectorArray::extend(const int64_t index, const GSpan values) { - GVArrayForGSpan varray{values}; + GVArray_For_GSpan varray{values}; this->extend(index, varray); } void GVectorArray::extend(IndexMask mask, const GVVectorArray &values) { for (const int i : mask) { - GVArrayForGVVectorArrayIndex array{values, i}; + GVArray_For_GVVectorArrayIndex array{values, i}; this->extend(i, array); } } void GVectorArray::extend(IndexMask mask, const GVectorArray &values) { - GVVectorArrayForGVectorArray virtual_values{values}; + GVVectorArray_For_GVectorArray virtual_values{values}; this->extend(mask, virtual_values); } diff --git a/source/blender/functions/intern/generic_virtual_array.cc b/source/blender/functions/intern/generic_virtual_array.cc index 9380eb257b2..e11501828f8 100644 --- a/source/blender/functions/intern/generic_virtual_array.cc +++ b/source/blender/functions/intern/generic_virtual_array.cc @@ -18,6 +18,10 @@ namespace blender::fn { +/* -------------------------------------------------------------------- + * GVArray. + */ + void GVArray::materialize_to_uninitialized(const IndexMask mask, void *dst) const { for (const int64_t i : mask) { @@ -37,7 +41,7 @@ bool GVArray::is_span_impl() const return false; } -GSpan GVArray::get_span_impl() const +GSpan GVArray::get_internal_span_impl() const { BLI_assert(false); return GSpan(*type_); @@ -48,60 +52,246 @@ bool GVArray::is_single_impl() const return false; } -void GVArray::get_single_impl(void *UNUSED(r_value)) const +void GVArray::get_internal_single_impl(void *UNUSED(r_value)) const { BLI_assert(false); } -void GVArrayForGSpan::get_impl(const int64_t index, void *r_value) const +const void *GVArray::try_get_internal_varray_impl() const +{ + return nullptr; +} + +/* -------------------------------------------------------------------- + * GVMutableArray. + */ + +void GVMutableArray::set_by_copy_impl(const int64_t index, const void *value) +{ + BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer); + type_->copy_to_uninitialized(value, buffer); + this->set_by_move_impl(index, buffer); + type_->destruct(buffer); +} + +void GVMutableArray::set_by_relocate_impl(const int64_t index, void *value) +{ + this->set_by_move_impl(index, value); + type_->destruct(value); +} + +void *GVMutableArray::try_get_internal_mutable_varray_impl() +{ + return nullptr; +} + +void GVMutableArray::fill(const void *value) +{ + if (this->is_span()) { + const GMutableSpan span = this->get_internal_span(); + type_->fill_initialized(value, span.data(), size_); + } + else { + for (int64_t i : IndexRange(size_)) { + this->set_by_copy(i, value); + } + } +} + +/* -------------------------------------------------------------------- + * GVArray_For_GSpan. + */ + +void GVArray_For_GSpan::get_impl(const int64_t index, void *r_value) const { type_->copy_to_initialized(POINTER_OFFSET(data_, element_size_ * index), r_value); } -void GVArrayForGSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const +void GVArray_For_GSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const { type_->copy_to_uninitialized(POINTER_OFFSET(data_, element_size_ * index), r_value); } -bool GVArrayForGSpan::is_span_impl() const +bool GVArray_For_GSpan::is_span_impl() const { return true; } -GSpan GVArrayForGSpan::get_span_impl() const +GSpan GVArray_For_GSpan::get_internal_span_impl() const { return GSpan(*type_, data_, size_); } -void GVArrayForSingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const +/* -------------------------------------------------------------------- + * GVMutableArray_For_GMutableSpan. + */ + +void GVMutableArray_For_GMutableSpan::get_impl(const int64_t index, void *r_value) const +{ + type_->copy_to_initialized(POINTER_OFFSET(data_, element_size_ * index), r_value); +} + +void GVMutableArray_For_GMutableSpan::get_to_uninitialized_impl(const int64_t index, + void *r_value) const +{ + type_->copy_to_uninitialized(POINTER_OFFSET(data_, element_size_ * index), r_value); +} + +void GVMutableArray_For_GMutableSpan::set_by_copy_impl(const int64_t index, const void *value) +{ + type_->copy_to_initialized(value, POINTER_OFFSET(data_, element_size_ * index)); +} + +void GVMutableArray_For_GMutableSpan::set_by_move_impl(const int64_t index, void *value) +{ + type_->move_to_initialized(value, POINTER_OFFSET(data_, element_size_ * index)); +} + +void GVMutableArray_For_GMutableSpan::set_by_relocate_impl(const int64_t index, void *value) +{ + type_->relocate_to_initialized(value, POINTER_OFFSET(data_, element_size_ * index)); +} + +bool GVMutableArray_For_GMutableSpan::is_span_impl() const +{ + return true; +} + +GSpan GVMutableArray_For_GMutableSpan::get_internal_span_impl() const +{ + return GSpan(*type_, data_, size_); +} + +/* -------------------------------------------------------------------- + * GVArray_For_SingleValueRef. + */ + +void GVArray_For_SingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const { type_->copy_to_initialized(value_, r_value); } -void GVArrayForSingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index), - void *r_value) const +void GVArray_For_SingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index), + void *r_value) const { type_->copy_to_uninitialized(value_, r_value); } -bool GVArrayForSingleValueRef::is_span_impl() const +bool GVArray_For_SingleValueRef::is_span_impl() const { return size_ == 1; } -GSpan GVArrayForSingleValueRef::get_span_impl() const +GSpan GVArray_For_SingleValueRef::get_internal_span_impl() const { return GSpan{*type_, value_, 1}; } -bool GVArrayForSingleValueRef::is_single_impl() const +bool GVArray_For_SingleValueRef::is_single_impl() const { return true; } -void GVArrayForSingleValueRef::get_single_impl(void *r_value) const +void GVArray_For_SingleValueRef::get_internal_single_impl(void *r_value) const { type_->copy_to_initialized(value_, r_value); } +/* -------------------------------------------------------------------- + * GVArray_For_SingleValue. + */ + +GVArray_For_SingleValue::GVArray_For_SingleValue(const CPPType &type, + const int64_t size, + const void *value) + : GVArray_For_SingleValueRef(type, size) +{ + value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); + type.copy_to_uninitialized(value, (void *)value_); +} + +GVArray_For_SingleValue::~GVArray_For_SingleValue() +{ + type_->destruct((void *)value_); + MEM_freeN((void *)value_); +} + +/* -------------------------------------------------------------------- + * GVArray_GSpan. + */ + +GVArray_GSpan::GVArray_GSpan(const GVArray &varray) : GSpan(varray.type()), varray_(varray) +{ + size_ = varray_.size(); + if (varray_.is_span()) { + data_ = varray_.get_internal_span().data(); + } + else { + owned_data_ = MEM_mallocN_aligned(type_->size() * size_, type_->alignment(), __func__); + varray_.materialize_to_uninitialized(IndexRange(size_), owned_data_); + data_ = owned_data_; + } +} + +GVArray_GSpan::~GVArray_GSpan() +{ + if (owned_data_ != nullptr) { + type_->destruct_n(owned_data_, size_); + MEM_freeN(owned_data_); + } +} + +/* -------------------------------------------------------------------- + * GVMutableArray_GSpan. + */ + +GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray &varray, const bool copy_values_to_span) + : GMutableSpan(varray.type()), varray_(varray) +{ + size_ = varray_.size(); + if (varray_.is_span()) { + data_ = varray_.get_internal_span().data(); + } + else { + owned_data_ = MEM_mallocN_aligned(type_->size() * size_, type_->alignment(), __func__); + if (copy_values_to_span) { + varray_.materialize_to_uninitialized(IndexRange(size_), owned_data_); + } + else { + type_->construct_default_n(owned_data_, size_); + } + data_ = owned_data_; + } +} + +GVMutableArray_GSpan::~GVMutableArray_GSpan() +{ + if (show_not_saved_warning_) { + if (!save_has_been_called_) { + std::cout << "Warning: Call `apply()` to make sure that changes persist in all cases.\n"; + } + } + if (owned_data_ != nullptr) { + type_->destruct_n(owned_data_, size_); + MEM_freeN(owned_data_); + } +} + +void GVMutableArray_GSpan::save() +{ + save_has_been_called_ = true; + if (data_ != owned_data_) { + return; + } + const int64_t element_size = type_->size(); + for (int64_t i : IndexRange(size_)) { + varray_.set_by_copy(i, POINTER_OFFSET(owned_data_, element_size * i)); + } +} + +void GVMutableArray_GSpan::disable_not_applied_warning() +{ + show_not_saved_warning_ = false; +} + } // namespace blender::fn diff --git a/source/blender/functions/intern/generic_virtual_vector_array.cc b/source/blender/functions/intern/generic_virtual_vector_array.cc index f6504cee41e..aa3d90883c6 100644 --- a/source/blender/functions/intern/generic_virtual_vector_array.cc +++ b/source/blender/functions/intern/generic_virtual_vector_array.cc @@ -18,48 +18,48 @@ namespace blender::fn { -void GVArrayForGVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const +void GVArray_For_GVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const { vector_array_.get_vector_element(index_, index_in_vector, r_value); } -void GVArrayForGVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector, - void *r_value) const +void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector, + void *r_value) const { type_->construct_default(r_value); vector_array_.get_vector_element(index_, index_in_vector, r_value); } -int64_t GVVectorArrayForSingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const +int64_t GVVectorArray_For_SingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const { return array_.size(); } -void GVVectorArrayForSingleGVArray::get_vector_element_impl(const int64_t UNUSED(index), - const int64_t index_in_vector, - void *r_value) const +void GVVectorArray_For_SingleGVArray::get_vector_element_impl(const int64_t UNUSED(index), + const int64_t index_in_vector, + void *r_value) const { array_.get(index_in_vector, r_value); } -bool GVVectorArrayForSingleGVArray::is_single_vector_impl() const +bool GVVectorArray_For_SingleGVArray::is_single_vector_impl() const { return true; } -int64_t GVVectorArrayForSingleGSpan::get_vector_size_impl(const int64_t UNUSED(index)) const +int64_t GVVectorArray_For_SingleGSpan::get_vector_size_impl(const int64_t UNUSED(index)) const { return span_.size(); } -void GVVectorArrayForSingleGSpan::get_vector_element_impl(const int64_t UNUSED(index), - const int64_t index_in_vector, - void *r_value) const +void GVVectorArray_For_SingleGSpan::get_vector_element_impl(const int64_t UNUSED(index), + const int64_t index_in_vector, + void *r_value) const { type_->copy_to_initialized(span_[index_in_vector], r_value); } -bool GVVectorArrayForSingleGSpan::is_single_vector_impl() const +bool GVVectorArray_For_SingleGSpan::is_single_vector_impl() const { return true; } diff --git a/source/blender/functions/intern/multi_function_network_evaluation.cc b/source/blender/functions/intern/multi_function_network_evaluation.cc index 86ac4f6a179..9a0cb0c35ce 100644 --- a/source/blender/functions/intern/multi_function_network_evaluation.cc +++ b/source/blender/functions/intern/multi_function_network_evaluation.cc @@ -974,11 +974,11 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__full(const MFInputS if (any_value->type == ValueType::OwnSingle) { OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value); if (value->is_single_allocated) { - return scope.construct<GVArrayForSingleValueRef>( + return scope.construct<GVArray_For_SingleValueRef>( __func__, value->span.type(), min_array_size_, value->span.data()); } - return scope.construct<GVArrayForGSpan>(__func__, value->span); + return scope.construct<GVArray_For_GSpan>(__func__, value->span); } if (any_value->type == ValueType::InputSingle) { InputSingleValue *value = static_cast<InputSingleValue *>(any_value); @@ -987,11 +987,11 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__full(const MFInputS if (any_value->type == ValueType::OutputSingle) { OutputSingleValue *value = static_cast<OutputSingleValue *>(any_value); BLI_assert(value->is_computed); - return scope.construct<GVArrayForGSpan>(__func__, value->span); + return scope.construct<GVArray_For_GSpan>(__func__, value->span); } BLI_assert(false); - return scope.construct<GVArrayForEmpty>(__func__, CPPType::get<float>()); + return scope.construct<GVArray_For_Empty>(__func__, CPPType::get<float>()); } const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInputSocket &socket, @@ -1004,7 +1004,7 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInpu if (any_value->type == ValueType::OwnSingle) { OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value); BLI_assert(value->span.size() == 1); - return scope.construct<GVArrayForGSpan>(__func__, value->span); + return scope.construct<GVArray_For_GSpan>(__func__, value->span); } if (any_value->type == ValueType::InputSingle) { InputSingleValue *value = static_cast<InputSingleValue *>(any_value); @@ -1015,11 +1015,11 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInpu OutputSingleValue *value = static_cast<OutputSingleValue *>(any_value); BLI_assert(value->is_computed); BLI_assert(value->span.size() == 1); - return scope.construct<GVArrayForGSpan>(__func__, value->span); + return scope.construct<GVArray_For_GSpan>(__func__, value->span); } BLI_assert(false); - return scope.construct<GVArrayForEmpty>(__func__, CPPType::get<float>()); + return scope.construct<GVArray_For_Empty>(__func__, CPPType::get<float>()); } const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full( @@ -1033,10 +1033,10 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full( OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value); if (value->vector_array->size() == 1) { GSpan span = (*value->vector_array)[0]; - return scope.construct<GVVectorArrayForSingleGSpan>(__func__, span, min_array_size_); + return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, span, min_array_size_); } - return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array); + return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array); } if (any_value->type == ValueType::InputVector) { InputVectorValue *value = static_cast<InputVectorValue *>(any_value); @@ -1044,11 +1044,11 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full( } if (any_value->type == ValueType::OutputVector) { OutputVectorValue *value = static_cast<OutputVectorValue *>(any_value); - return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array); + return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array); } BLI_assert(false); - return scope.construct<GVVectorArrayForSingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0); + return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0); } const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single( @@ -1061,7 +1061,7 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single( if (any_value->type == ValueType::OwnVector) { OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value); BLI_assert(value->vector_array->size() == 1); - return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array); + return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array); } if (any_value->type == ValueType::InputVector) { InputVectorValue *value = static_cast<InputVectorValue *>(any_value); @@ -1071,11 +1071,11 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single( if (any_value->type == ValueType::OutputVector) { OutputVectorValue *value = static_cast<OutputVectorValue *>(any_value); BLI_assert(value->vector_array->size() == 1); - return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array); + return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array); } BLI_assert(false); - return scope.construct<GVVectorArrayForSingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0); + return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0); } /** \} */ diff --git a/source/blender/functions/tests/FN_multi_function_network_test.cc b/source/blender/functions/tests/FN_multi_function_network_test.cc index 51e116b5983..7b9738e5ca4 100644 --- a/source/blender/functions/tests/FN_multi_function_network_test.cc +++ b/source/blender/functions/tests/FN_multi_function_network_test.cc @@ -223,7 +223,7 @@ TEST(multi_function_network, Test2) Array<int> output_value_2(5, -1); MFParamsBuilder params(network_fn, 5); - GVVectorArrayForSingleGSpan inputs_1{input_value_1.as_span(), 5}; + GVVectorArray_For_SingleGSpan inputs_1{input_value_1.as_span(), 5}; params.add_readonly_vector_input(inputs_1); params.add_readonly_single_input(&input_value_2); params.add_vector_output(output_value_1); |