Changeset View
Changeset View
Standalone View
Standalone View
source/blender/functions/FN_generic_virtual_array.hh
| Show All 17 Lines | |||||
| /** \file | /** \file | ||||
| * \ingroup fn | * \ingroup fn | ||||
| * | * | ||||
| * A generic virtual array is the same as a virtual array from blenlib, except for the fact that | * A generic virtual array is the same as a virtual array from blenlib, except for the fact that | ||||
| * the data type is only known at runtime. | * the data type is only known at runtime. | ||||
| */ | */ | ||||
| #include <optional> | |||||
| #include "BLI_virtual_array.hh" | #include "BLI_virtual_array.hh" | ||||
| #include "FN_generic_span.hh" | #include "FN_generic_span.hh" | ||||
| namespace blender::fn { | namespace blender::fn { | ||||
| template<typename T> class GVArray_Typed; | |||||
| template<typename T> class GVMutableArray_Typed; | |||||
| /* A generically typed version of `VArray<T>`. */ | /* A generically typed version of `VArray<T>`. */ | ||||
| class GVArray { | class GVArray { | ||||
| protected: | protected: | ||||
| const CPPType *type_; | const CPPType *type_; | ||||
| int64_t size_; | int64_t size_; | ||||
| public: | public: | ||||
| GVArray(const CPPType &type, const int64_t size) : type_(&type), size_(size) | GVArray(const CPPType &type, const int64_t size) : type_(&type), size_(size) | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | bool is_span() const | ||||
| if (size_ == 0) { | if (size_ == 0) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| return this->is_span_impl(); | return this->is_span_impl(); | ||||
| } | } | ||||
| /* Returns the internally used span of the virtual array. This invokes undefined behavior is the | /* Returns the internally used span of the virtual array. This invokes undefined behavior is the | ||||
| * virtual array is not stored as a span internally. */ | * virtual array is not stored as a span internally. */ | ||||
| GSpan get_span() const | GSpan get_internal_span() const | ||||
| { | { | ||||
| BLI_assert(this->is_span()); | BLI_assert(this->is_span()); | ||||
| if (size_ == 0) { | if (size_ == 0) { | ||||
| return GSpan(*type_); | 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. */ | /* Returns true when the virtual array returns the same value for every index. */ | ||||
| bool is_single() const | bool is_single() const | ||||
| { | { | ||||
| if (size_ == 1) { | if (size_ == 1) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| return this->is_single_impl(); | return this->is_single_impl(); | ||||
| } | } | ||||
| /* Copies the value that is used for every element into `r_value`, which is expected to point to | /* 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 | * initialized memory. This invokes undefined behavior if the virtual array would not return the | ||||
| * same value for every index. */ | * 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()); | BLI_assert(this->is_single()); | ||||
| if (size_ == 1) { | if (size_ == 1) { | ||||
| this->get(0, r_value); | 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 | void get_single_to_uninitialized(void *r_value) const | ||||
| { | { | ||||
| type_->construct_default(r_value); | 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; | 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: | protected: | ||||
| virtual void get_impl(const int64_t index, void *r_value) const; | 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 void get_to_uninitialized_impl(const int64_t index, void *r_value) const = 0; | ||||
| virtual bool is_span_impl() const; | 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 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 { | using GVArrayPtr = std::unique_ptr<GVArray>; | ||||
| using GVMutableArrayPtr = std::unique_ptr<GVMutableArray>; | |||||
| class GVArray_For_GSpan : public GVArray { | |||||
| protected: | protected: | ||||
| const void *data_; | const void *data_ = nullptr; | ||||
| const int64_t element_size_; | const int64_t element_size_; | ||||
| public: | public: | ||||
| GVArrayForGSpan(const GSpan span) | GVArray_For_GSpan(const GSpan span) | ||||
| : GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size()) | : GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size()) | ||||
| { | { | ||||
| } | } | ||||
| protected: | 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_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 get_to_uninitialized_impl(const int64_t index, void *r_value) const override; | ||||
| bool is_span_impl() 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: | public: | ||||
| GVArrayForEmpty(const CPPType &type) : GVArray(type, 0) | GVArray_For_Empty(const CPPType &type) : GVArray(type, 0) | ||||
| { | { | ||||
| } | } | ||||
| protected: | protected: | ||||
| void get_to_uninitialized_impl(const int64_t UNUSED(index), void *UNUSED(r_value)) const override | void get_to_uninitialized_impl(const int64_t UNUSED(index), void *UNUSED(r_value)) const override | ||||
| { | { | ||||
| BLI_assert(false); | BLI_assert(false); | ||||
| } | } | ||||
| }; | }; | ||||
| class GVArrayForSingleValueRef : public GVArray { | class GVMutableArray_For_GMutableSpan : public GVMutableArray { | ||||
| private: | protected: | ||||
| const void *value_; | 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: | 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) | : GVArray(type, size), value_(value) | ||||
| { | { | ||||
| } | } | ||||
| protected: | 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_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 get_to_uninitialized_impl(const int64_t index, void *r_value) const override; | ||||
| bool is_span_impl() 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; | 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 { | /* Same as GVArray_For_SingleValueRef, but the value is owned. */ | ||||
| private: | class GVArray_For_SingleValue : public GVArray_For_SingleValueRef { | ||||
| const VArray<T> &array_; | 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: | public: | ||||
| GVArrayForVArray(const VArray<T> &array) | GVArray_For_VArray(const VArray<T> &varray) | ||||
| : GVArray(CPPType::get<T>(), array.size()), array_(array) | : GVArray(CPPType::get<T>(), varray.size()), varray_(&varray) | ||||
| { | { | ||||
| } | } | ||||
| protected: | 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 | 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 | 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 | 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 | 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> { | /* Used to convert any generic virtual array into a typed one. */ | ||||
| private: | template<typename T> class VArray_For_GVArray : public VArray<T> { | ||||
| const GVArray &array_; | protected: | ||||
| const GVArray *varray_ = nullptr; | |||||
| public: | 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(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; | |||||
| varray_->get(index, &value); | |||||
| return value; | |||||
| } | |||||
| bool is_span_impl() const override | |||||
| { | |||||
| return varray_->is_span(); | |||||
| } | |||||
| Span<T> get_internal_span_impl() const override | |||||
| { | { | ||||
| BLI_assert(array_.type().template is<T>()); | 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 an generic mutable virtual array into a typed one. */ | |||||
| template<typename T> class VMutableArray_For_GVMutableArray : public VMutableArray<T> { | |||||
| protected: | 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) | |||||
| { | |||||
| } | |||||
| private: | |||||
| T get_impl(const int64_t index) const override | T get_impl(const int64_t index) const override | ||||
| { | { | ||||
| T value; | T value; | ||||
| array_.get(index, &value); | varray_->get(index, &value); | ||||
| return 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 | 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 | bool is_single_impl() const override | ||||
| { | { | ||||
| return array_.is_single(); | return varray_->is_single(); | ||||
| } | } | ||||
| T get_single_impl() const override | T get_internal_single_impl() const override | ||||
| { | { | ||||
| T value; | T value; | ||||
| array_.get_single(&value); | varray_->get_internal_single(&value); | ||||
| return 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: | |||||
| VArrayPtr<T> owned_varray_; | |||||
| public: | |||||
| /* Takes ownership of varray and passes a reference to the base class. */ | |||||
| GVArray_For_OwnedVArray(VArrayPtr<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: | |||||
| GVArrayPtr owned_varray_; | |||||
| public: | |||||
| /* Takes ownership of varray and passes a reference to the base class. */ | |||||
| VArray_For_OwnedGVArray(GVArrayPtr varray) | |||||
| : VArray_For_GVArray<T>(*varray), owned_varray_(std::move(varray)) | |||||
| { | |||||
| } | |||||
| }; | |||||
| template<typename T> | |||||
| class GVMutableArray_For_OwnedVMutableArray : public GVMutableArray_For_VMutableArray<T> { | |||||
| private: | |||||
| VMutableArrayPtr<T> owned_varray_; | |||||
| public: | |||||
| /* Takes ownership of varray and passes a reference to the base class. */ | |||||
| GVMutableArray_For_OwnedVMutableArray(VMutableArrayPtr<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: | |||||
| GVMutableArrayPtr owned_varray_; | |||||
| public: | |||||
| /* Takes ownership of varray and passes a reference to the base class. */ | |||||
| VMutableArray_For_OwnedGVMutableArray(GVMutableArrayPtr 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_; | |||||
| GVArrayPtr 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(GVArrayPtr 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_; | |||||
| GVMutableArrayPtr 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(GVMutableArrayPtr 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 | } // namespace blender::fn | ||||