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')
-rw-r--r--source/blender/functions/FN_field.hh66
-rw-r--r--source/blender/functions/FN_generic_vector_array.hh3
-rw-r--r--source/blender/functions/FN_generic_virtual_array.hh1252
-rw-r--r--source/blender/functions/FN_generic_virtual_vector_array.hh14
-rw-r--r--source/blender/functions/FN_multi_function_params.hh26
-rw-r--r--source/blender/functions/intern/field.cc164
-rw-r--r--source/blender/functions/intern/generic_vector_array.cc5
-rw-r--r--source/blender/functions/intern/generic_virtual_array.cc642
-rw-r--r--source/blender/functions/intern/generic_virtual_vector_array.cc10
-rw-r--r--source/blender/functions/intern/multi_function_parallel.cc4
-rw-r--r--source/blender/functions/intern/multi_function_procedure_executor.cc3
-rw-r--r--source/blender/functions/tests/FN_field_test.cc50
-rw-r--r--source/blender/functions/tests/FN_multi_function_procedure_test.cc37
13 files changed, 1244 insertions, 1032 deletions
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index 5e0302130af..fb488fdbfa9 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -248,9 +248,9 @@ class FieldInput : public FieldNode {
* Get the value of this specific input based on the given context. The returned virtual array,
* should live at least as long as the passed in #scope. May return null.
*/
- virtual const GVArray *get_varray_for_context(const FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const = 0;
+ virtual GVArray get_varray_for_context(const FieldContext &context,
+ IndexMask mask,
+ ResourceScope &scope) const = 0;
virtual std::string socket_inspection_name() const;
blender::StringRef debug_name() const;
@@ -268,9 +268,9 @@ class FieldContext {
public:
~FieldContext() = default;
- virtual const GVArray *get_varray_for_input(const FieldInput &field_input,
- IndexMask mask,
- ResourceScope &scope) const;
+ virtual GVArray get_varray_for_input(const FieldInput &field_input,
+ IndexMask mask,
+ ResourceScope &scope) const;
};
/**
@@ -289,8 +289,8 @@ class FieldEvaluator : NonMovable, NonCopyable {
const FieldContext &context_;
const IndexMask mask_;
Vector<GField> fields_to_evaluate_;
- Vector<GVMutableArray *> dst_varrays_;
- Vector<const GVArray *> evaluated_varrays_;
+ Vector<GVMutableArray> dst_varrays_;
+ Vector<GVArray> evaluated_varrays_;
Vector<OutputPointerInfo> output_pointer_infos_;
bool is_evaluated_ = false;
@@ -317,13 +317,12 @@ class FieldEvaluator : NonMovable, NonCopyable {
* \param field: Field to add to the evaluator.
* \param dst: Mutable virtual array that the evaluated result for this field is be written into.
*/
- int add_with_destination(GField field, GVMutableArray &dst);
+ int add_with_destination(GField field, GVMutableArray dst);
/** Same as #add_with_destination but typed. */
- template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> &dst)
+ template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> dst)
{
- GVMutableArray &varray = scope_.construct<GVMutableArray_For_VMutableArray<T>>(dst);
- return this->add_with_destination(GField(std::move(field)), varray);
+ return this->add_with_destination(GField(std::move(field)), GVMutableArray(std::move(dst)));
}
/**
@@ -342,11 +341,10 @@ class FieldEvaluator : NonMovable, NonCopyable {
*/
template<typename T> int add_with_destination(Field<T> field, MutableSpan<T> dst)
{
- GVMutableArray &varray = scope_.construct<GVMutableArray_For_MutableSpan<T>>(dst);
- return this->add_with_destination(std::move(field), varray);
+ return this->add_with_destination(std::move(field), VMutableArray<T>::ForSpan(dst));
}
- int add(GField field, const GVArray **varray_ptr);
+ int add(GField field, GVArray *varray_ptr);
/**
* \param field: Field to add to the evaluator.
@@ -354,14 +352,14 @@ class FieldEvaluator : NonMovable, NonCopyable {
* assigned to the given position.
* \return Index of the field in the evaluator which can be used in the #get_evaluated methods.
*/
- template<typename T> int add(Field<T> field, const VArray<T> **varray_ptr)
+ template<typename T> int add(Field<T> field, VArray<T> *varray_ptr)
{
const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
- dst_varrays_.append(nullptr);
- output_pointer_infos_.append(
- OutputPointerInfo{varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &scope) {
- *(const VArray<T> **)dst = &*scope.construct<GVArray_Typed<T>>(varray);
- }});
+ dst_varrays_.append({});
+ output_pointer_infos_.append(OutputPointerInfo{
+ varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &UNUSED(scope)) {
+ *(VArray<T> *)dst = varray.typed<T>();
+ }});
return field_index;
}
@@ -378,14 +376,12 @@ class FieldEvaluator : NonMovable, NonCopyable {
const GVArray &get_evaluated(const int field_index) const
{
BLI_assert(is_evaluated_);
- return *evaluated_varrays_[field_index];
+ return evaluated_varrays_[field_index];
}
- template<typename T> const VArray<T> &get_evaluated(const int field_index)
+ template<typename T> VArray<T> get_evaluated(const int field_index)
{
- const GVArray &varray = this->get_evaluated(field_index);
- GVArray_Typed<T> &typed_varray = scope_.construct<GVArray_Typed<T>>(varray);
- return *typed_varray;
+ return this->get_evaluated(field_index).typed<T>();
}
/**
@@ -396,11 +392,11 @@ class FieldEvaluator : NonMovable, NonCopyable {
IndexMask get_evaluated_as_mask(const int field_index);
};
-Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
- Span<GFieldRef> fields_to_evaluate,
- IndexMask mask,
- const FieldContext &context,
- Span<GVMutableArray *> dst_varrays = {});
+Vector<GVArray> evaluate_fields(ResourceScope &scope,
+ Span<GFieldRef> fields_to_evaluate,
+ IndexMask mask,
+ const FieldContext &context,
+ Span<GVMutableArray> dst_varrays = {});
/* -------------------------------------------------------------------- */
/** \name Utility functions for simple field creation and evaluation
@@ -429,11 +425,11 @@ class IndexFieldInput final : public FieldInput {
public:
IndexFieldInput();
- static GVArray *get_index_varray(IndexMask mask, ResourceScope &scope);
+ static GVArray get_index_varray(IndexMask mask, ResourceScope &scope);
- const GVArray *get_varray_for_context(const FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const final;
+ GVArray get_varray_for_context(const FieldContext &context,
+ IndexMask mask,
+ ResourceScope &scope) const final;
uint64_t hash() const override;
bool is_equal_to(const fn::FieldNode &other) const override;
diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/functions/FN_generic_vector_array.hh
index 179e85671f8..57efa1b5ba9 100644
--- a/source/blender/functions/FN_generic_vector_array.hh
+++ b/source/blender/functions/FN_generic_vector_array.hh
@@ -125,8 +125,7 @@ template<typename T> class GVectorArray_TypedMutableRef {
void extend(const int64_t index, const VArray<T> &values)
{
- GVArray_For_VArray<T> array{values};
- this->extend(index, array);
+ vector_array_->extend(index, values);
}
MutableSpan<T> operator[](const int64_t index)
diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh
index 8aad017e68b..5d33a05a693 100644
--- a/source/blender/functions/FN_generic_virtual_array.hh
+++ b/source/blender/functions/FN_generic_virtual_array.hh
@@ -23,8 +23,7 @@
* the data type is only known at runtime.
*/
-#include <optional>
-
+#include "BLI_timeit.hh"
#include "BLI_virtual_array.hh"
#include "FN_generic_array.hh"
@@ -32,940 +31,845 @@
namespace blender::fn {
-template<typename T> class GVArray_Typed;
-template<typename T> class GVMutableArray_Typed;
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl and #GVMutableArrayImpl.
+ * \{ */
class GVArray;
+class GVArrayImpl;
class GVMutableArray;
+class GVMutableArrayImpl;
-using GVArrayPtr = std::unique_ptr<GVArray>;
-using GVMutableArrayPtr = std::unique_ptr<GVMutableArray>;
-
-/* A generically typed version of `VArray<T>`. */
-class GVArray {
+/* A generically typed version of #VArrayImpl. */
+class GVArrayImpl {
protected:
const CPPType *type_;
int64_t size_;
public:
- GVArray(const CPPType &type, const int64_t size) : type_(&type), size_(size)
- {
- BLI_assert(size_ >= 0);
- }
+ GVArrayImpl(const CPPType &type, const int64_t size);
+ virtual ~GVArrayImpl() = default;
- virtual ~GVArray() = default;
+ const CPPType &type() const;
- const CPPType &type() const
- {
- return *type_;
- }
+ int64_t size() const;
- int64_t size() const
- {
- return size_;
- }
+ virtual void get(const int64_t index, void *r_value) const;
+ virtual void get_to_uninitialized(const int64_t index, void *r_value) const = 0;
- bool is_empty() const
- {
- return size_ == 0;
- }
+ virtual bool is_span() const;
+ virtual GSpan get_internal_span() const;
- /* Copies the value at the given index into the provided storage. The `r_value` pointer is
- * expected to point to initialized memory. */
- void get(const int64_t index, void *r_value) const
- {
- BLI_assert(index >= 0);
- BLI_assert(index < size_);
- this->get_impl(index, r_value);
- }
+ virtual bool is_single() const;
+ virtual void get_internal_single(void *UNUSED(r_value)) const;
- /* Same as `get`, but `r_value` is expected to point to uninitialized memory. */
- void get_to_uninitialized(const int64_t index, void *r_value) const
- {
- BLI_assert(index >= 0);
- BLI_assert(index < size_);
- this->get_to_uninitialized_impl(index, r_value);
- }
+ virtual void materialize(const IndexMask mask, void *dst) const;
+ virtual void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
- /* Returns true when the virtual array is stored as a span internally. */
- bool is_span() const
- {
- if (size_ == 0) {
- return true;
- }
- return this->is_span_impl();
- }
+ virtual bool try_assign_VArray(void *varray) const;
+ virtual bool may_have_ownership() const;
+};
- /* 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_internal_span() const
- {
- BLI_assert(this->is_span());
- if (size_ == 0) {
- return GSpan(*type_);
- }
- return this->get_internal_span_impl();
- }
+/* A generic version of #VMutableArrayImpl. */
+class GVMutableArrayImpl : public GVArrayImpl {
+ public:
+ GVMutableArrayImpl(const CPPType &type, const int64_t size);
- /* Returns true when the virtual array returns the same value for every index. */
- bool is_single() const
- {
- if (size_ == 1) {
- return true;
- }
- return this->is_single_impl();
- }
+ virtual void set_by_copy(const int64_t index, const void *value);
+ virtual void set_by_relocate(const int64_t index, void *value);
+ virtual void set_by_move(const int64_t index, void *value) = 0;
- /* Copies the value that is used for every element into `r_value`, which is expected to point to
- * initialized memory. This invokes undefined behavior if the virtual array would not return the
- * same value for every index. */
- void get_internal_single(void *r_value) const
- {
- BLI_assert(this->is_single());
- if (size_ == 1) {
- this->get(0, r_value);
- return;
- }
- this->get_internal_single_impl(r_value);
- }
+ virtual void set_all(const void *src);
- /* Same as `get_internal_single`, but `r_value` points to initialized memory. */
- void get_internal_single_to_uninitialized(void *r_value) const
- {
- type_->default_construct(r_value);
- this->get_internal_single(r_value);
- }
+ virtual bool try_assign_VMutableArray(void *varray) const;
+};
- void materialize(void *dst) const;
- void materialize(const IndexMask mask, void *dst) const;
+/** \} */
- void materialize_to_uninitialized(void *dst) const;
- void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
+/* -------------------------------------------------------------------- */
+/** \name #GVArray and #GVMutableArray
+ * \{ */
- 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();
- }
+namespace detail {
+struct GVArrayAnyExtraInfo {
+ const GVArrayImpl *(*get_varray)(const void *buffer) =
+ [](const void *UNUSED(buffer)) -> const GVArrayImpl * { return nullptr; };
- /* Create a typed virtual array for this generic virtual array. */
- template<typename T> GVArray_Typed<T> typed() const
- {
- return GVArray_Typed<T>(*this);
- }
+ template<typename StorageT> static GVArrayAnyExtraInfo get();
+};
+} // namespace detail
- GVArrayPtr shallow_copy() const;
+class GVMutableArray;
+/**
+ * Utility class to reduce code duplication between #GVArray and #GVMutableArray.
+ * It pretty much follows #VArrayCommon. Don't use this class outside of this header.
+ */
+class GVArrayCommon {
protected:
- 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;
+ /**
+ * See #VArrayCommon for more information. The inline buffer is a bit larger here, because
+ * generic virtual array implementations often require a bit more space than typed ones.
+ */
+ using Storage = Any<detail::GVArrayAnyExtraInfo, 40, 8>;
- virtual bool is_span_impl() const;
- virtual GSpan get_internal_span_impl() const;
+ const GVArrayImpl *impl_ = nullptr;
+ Storage storage_;
- virtual bool is_single_impl() const;
- virtual void get_internal_single_impl(void *UNUSED(r_value)) const;
+ protected:
+ GVArrayCommon();
+ GVArrayCommon(const GVArrayCommon &other);
+ GVArrayCommon(GVArrayCommon &&other) noexcept;
+ GVArrayCommon(const GVArrayImpl *impl);
+ GVArrayCommon(std::shared_ptr<const GVArrayImpl> impl);
+ ~GVArrayCommon();
- virtual void materialize_impl(const IndexMask mask, void *dst) const;
- virtual void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const;
+ template<typename ImplT, typename... Args> void emplace(Args &&...args);
- virtual const void *try_get_internal_varray_impl() const;
-};
+ void copy_from(const GVArrayCommon &other);
+ void move_from(GVArrayCommon &&other) noexcept;
+
+ const GVArrayImpl *impl_from_storage() 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)
- {
- }
+ const CPPType &type() const;
+ operator bool() const;
- 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);
- }
+ int64_t size() const;
+ bool is_empty() const;
+ IndexRange index_range() const;
- 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);
- }
+ template<typename T> bool try_assign_VArray(VArray<T> &varray) const;
+ bool may_have_ownership() const;
- 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);
- }
+ void materialize(void *dst) const;
+ void materialize(const IndexMask mask, void *dst) const;
- 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());
- }
+ void materialize_to_uninitialized(void *dst) const;
+ void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
- 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();
- }
+ bool is_span() const;
+ GSpan get_internal_span() const;
- /* Create a typed virtual array for this generic virtual array. */
- template<typename T> GVMutableArray_Typed<T> typed()
- {
- return GVMutableArray_Typed<T>(*this);
- }
+ bool is_single() const;
+ void get_internal_single(void *r_value) const;
+ void get_internal_single_to_uninitialized(void *r_value) const;
- void fill(const void *value);
+ void get(const int64_t index, void *r_value) const;
+ void get_to_uninitialized(const int64_t index, void *r_value) const;
+};
- /* Copy the values from the source buffer to all elements in the virtual array. */
- void set_all(const void *src)
- {
- this->set_all_impl(src);
- }
+/** Generic version of #VArray. */
+class GVArray : public GVArrayCommon {
+ private:
+ friend GVMutableArray;
- 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;
+ public:
+ GVArray() = default;
- virtual void set_all_impl(const void *src);
+ GVArray(const GVArray &other);
+ GVArray(GVArray &&other) noexcept;
+ GVArray(const GVArrayImpl *impl);
+ GVArray(std::shared_ptr<const GVArrayImpl> impl);
- virtual void *try_get_internal_mutable_varray_impl();
-};
+ template<typename T> GVArray(const VArray<T> &varray);
+ template<typename T> VArray<T> typed() const;
-class GVArray_For_GSpan : public GVArray {
- protected:
- const void *data_ = nullptr;
- const int64_t element_size_;
+ template<typename ImplT, typename... Args> static GVArray For(Args &&...args);
- public:
- GVArray_For_GSpan(const GSpan span)
- : GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size())
- {
- }
+ static GVArray ForSingle(const CPPType &type, const int64_t size, const void *value);
+ static GVArray ForSingleRef(const CPPType &type, const int64_t size, const void *value);
+ static GVArray ForSingleDefault(const CPPType &type, const int64_t size);
+ static GVArray ForSpan(GSpan span);
+ static GVArray ForGArray(GArray<> array);
+ static GVArray ForEmpty(const CPPType &type);
- protected:
- GVArray_For_GSpan(const CPPType &type, const int64_t size)
- : GVArray(type, size), element_size_(type.size())
- {
- }
+ GVArray slice(IndexRange slice) const;
- 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;
+ GVArray &operator=(const GVArray &other);
+ GVArray &operator=(GVArray &&other) noexcept;
- bool is_span_impl() const override;
- GSpan get_internal_span_impl() const override;
+ const GVArrayImpl *get_implementation() const
+ {
+ return impl_;
+ }
};
-class GVArray_For_Empty : public GVArray {
+/** Generic version of #VMutableArray. */
+class GVMutableArray : public GVArrayCommon {
public:
- GVArray_For_Empty(const CPPType &type) : GVArray(type, 0)
- {
- }
+ GVMutableArray() = default;
+ GVMutableArray(const GVMutableArray &other);
+ GVMutableArray(GVMutableArray &&other) noexcept;
+ GVMutableArray(GVMutableArrayImpl *impl);
+ GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl);
- protected:
- void get_to_uninitialized_impl(const int64_t UNUSED(index), void *UNUSED(r_value)) const override
- {
- BLI_assert(false);
- }
-};
+ template<typename T> GVMutableArray(const VMutableArray<T> &varray);
+ template<typename T> VMutableArray<T> typed() const;
-class GVMutableArray_For_GMutableSpan : public GVMutableArray {
- protected:
- void *data_ = nullptr;
- const int64_t element_size_;
+ template<typename ImplT, typename... Args> static GVMutableArray For(Args &&...args);
- public:
- GVMutableArray_For_GMutableSpan(const GMutableSpan span)
- : GVMutableArray(span.type(), span.size()),
- data_(span.data()),
- element_size_(span.type().size())
- {
- }
+ static GVMutableArray ForSpan(GMutableSpan span);
- protected:
- GVMutableArray_For_GMutableSpan(const CPPType &type, const int64_t size)
- : GVMutableArray(type, size), element_size_(type.size())
- {
- }
+ operator GVArray() const &;
+ operator GVArray() &&noexcept;
- 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;
+ GVMutableArray &operator=(const GVMutableArray &other);
+ GVMutableArray &operator=(GVMutableArray &&other) noexcept;
- 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;
+ GMutableSpan get_internal_span() const;
- bool is_span_impl() const override;
- GSpan get_internal_span_impl() const override;
-};
+ template<typename T> bool try_assign_VMutableArray(VMutableArray<T> &varray) const;
-/* 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;
+ void set_by_copy(const int64_t index, const void *value);
+ void set_by_move(const int64_t index, void *value);
+ void set_by_relocate(const int64_t index, void *value);
- public:
- GVArray_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
- : GVArray(type, size), value_(value)
- {
- }
+ void fill(const void *value);
+ void set_all(const void *src);
- protected:
- GVArray_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArray(type, size)
- {
- }
+ GVMutableArrayImpl *get_implementation() const;
- 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;
+ private:
+ GVMutableArrayImpl *get_impl() const;
+};
- bool is_span_impl() const override;
- GSpan get_internal_span_impl() const override;
+/** \} */
- bool is_single_impl() const override;
- void get_internal_single_impl(void *r_value) const override;
+/* -------------------------------------------------------------------- */
+/** \name #GVArray_GSpan and #GVMutableArray_GSpan.
+ * \{ */
+
+/* A generic version of VArray_Span. */
+class GVArray_GSpan : public GSpan {
+ private:
+ GVArray varray_;
+ void *owned_data_ = nullptr;
+
+ public:
+ GVArray_GSpan(GVArray varray);
+ ~GVArray_GSpan();
};
-/* Same as GVArray_For_SingleValueRef, but the value is owned. */
-class GVArray_For_SingleValue : public GVArray_For_SingleValueRef {
+/* 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:
- GVArray_For_SingleValue(const CPPType &type, const int64_t size, const void *value);
- ~GVArray_For_SingleValue();
+ GVMutableArray_GSpan(GVMutableArray varray, bool copy_values_to_span = true);
+ ~GVMutableArray_GSpan();
+
+ void save();
+ void disable_not_applied_warning();
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Conversions between generic and typed virtual arrays.
+ * \{ */
+
/* Used to convert a typed virtual array into a generic one. */
-template<typename T> class GVArray_For_VArray : public GVArray {
+template<typename T> class GVArrayImpl_For_VArray : public GVArrayImpl {
protected:
- const VArray<T> *varray_ = nullptr;
+ VArray<T> varray_;
public:
- GVArray_For_VArray(const VArray<T> &varray)
- : GVArray(CPPType::get<T>(), varray.size()), varray_(&varray)
+ GVArrayImpl_For_VArray(VArray<T> varray)
+ : GVArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray))
{
}
protected:
- GVArray_For_VArray(const int64_t size) : GVArray(CPPType::get<T>(), size)
+ void get(const int64_t index, void *r_value) const override
{
+ *(T *)r_value = varray_[index];
}
- void get_impl(const int64_t index, void *r_value) const override
+ void get_to_uninitialized(const int64_t index, void *r_value) const override
{
- *(T *)r_value = varray_->get(index);
+ new (r_value) T(varray_[index]);
}
- void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ bool is_span() const override
{
- new (r_value) T(varray_->get(index));
+ return varray_.is_span();
}
- bool is_span_impl() const override
+ GSpan get_internal_span() const override
{
- return varray_->is_span();
+ return GSpan(varray_.get_internal_span());
}
- GSpan get_internal_span_impl() const override
+ bool is_single() const override
{
- return GSpan(varray_->get_internal_span());
+ return varray_.is_single();
}
- bool is_single_impl() const override
+ void get_internal_single(void *r_value) const override
{
- return varray_->is_single();
+ *(T *)r_value = varray_.get_internal_single();
}
- void get_internal_single_impl(void *r_value) const override
+ void materialize(const IndexMask mask, void *dst) const override
{
- *(T *)r_value = varray_->get_internal_single();
+ varray_.materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
- void materialize_impl(const IndexMask mask, void *dst) const override
+ void materialize_to_uninitialized(const IndexMask mask, void *dst) const override
{
- varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
+ varray_.materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
- void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override
+ bool try_assign_VArray(void *varray) const override
{
- varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
+ *(VArray<T> *)varray = varray_;
+ return true;
}
- const void *try_get_internal_varray_impl() const override
- {
- return varray_;
- }
-};
-
-class GVArray_For_GArray : public GVArray_For_GSpan {
- protected:
- GArray<> array_;
-
- public:
- GVArray_For_GArray(GArray<> array) : GVArray_For_GSpan(array.as_span()), array_(std::move(array))
+ bool may_have_ownership() const override
{
+ return varray_.may_have_ownership();
}
};
/* Used to convert any generic virtual array into a typed one. */
-template<typename T> class VArray_For_GVArray : public VArray<T> {
+template<typename T> class VArrayImpl_For_GVArray : public VArrayImpl<T> {
protected:
- const GVArray *varray_ = nullptr;
+ GVArray varray_;
public:
- VArray_For_GVArray(const GVArray &varray) : VArray<T>(varray.size()), varray_(&varray)
+ VArrayImpl_For_GVArray(GVArray varray) : VArrayImpl<T>(varray.size()), varray_(std::move(varray))
{
- BLI_assert(varray_->type().template is<T>());
+ BLI_assert(varray_);
+ BLI_assert(varray_.type().is<T>());
}
protected:
- VArray_For_GVArray(const int64_t size) : VArray<T>(size)
- {
- }
-
- T get_impl(const int64_t index) const override
+ T get(const int64_t index) const override
{
T value;
- varray_->get(index, &value);
+ varray_.get(index, &value);
return value;
}
- bool is_span_impl() const override
+ bool is_span() const override
{
- return varray_->is_span();
+ return varray_.is_span();
}
- Span<T> get_internal_span_impl() const override
+ Span<T> get_internal_span() const override
{
- return varray_->get_internal_span().template typed<T>();
+ return varray_.get_internal_span().template typed<T>();
}
- bool is_single_impl() const override
+ bool is_single() const override
{
- return varray_->is_single();
+ return varray_.is_single();
}
- T get_internal_single_impl() const override
+ T get_internal_single() const override
{
T value;
- varray_->get_internal_single(&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)
- {
- }
-
- private:
- T get_impl(const int64_t index) const override
- {
- T 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
+ bool try_assign_GVArray(GVArray &varray) const override
{
- return varray_->get_internal_span().template typed<T>();
+ varray = varray_;
+ return true;
}
- bool is_single_impl() const override
+ bool may_have_ownership() const override
{
- return varray_->is_single();
- }
-
- T get_internal_single_impl() const override
- {
- T value;
- varray_->get_internal_single(&value);
- return value;
+ return varray_.may_have_ownership();
}
};
/* Used to convert any typed virtual mutable array into a generic one. */
-template<typename T> class GVMutableArray_For_VMutableArray : public GVMutableArray {
+template<typename T> class GVMutableArrayImpl_For_VMutableArray : public GVMutableArrayImpl {
protected:
- VMutableArray<T> *varray_ = nullptr;
+ VMutableArray<T> varray_;
public:
- GVMutableArray_For_VMutableArray(VMutableArray<T> &varray)
- : GVMutableArray(CPPType::get<T>(), varray.size()), varray_(&varray)
+ GVMutableArrayImpl_For_VMutableArray(VMutableArray<T> varray)
+ : GVMutableArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray))
{
}
protected:
- GVMutableArray_For_VMutableArray(const int64_t size) : GVMutableArray(CPPType::get<T>(), size)
+ void get(const int64_t index, void *r_value) const override
{
+ *(T *)r_value = varray_[index];
}
- void get_impl(const int64_t index, void *r_value) const override
+ void get_to_uninitialized(const int64_t index, void *r_value) const override
{
- *(T *)r_value = varray_->get(index);
+ new (r_value) T(varray_[index]);
}
- void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ bool is_span() const override
{
- new (r_value) T(varray_->get(index));
+ return varray_.is_span();
}
- bool is_span_impl() const override
+ GSpan get_internal_span() const override
{
- return varray_->is_span();
- }
-
- GSpan get_internal_span_impl() const override
- {
- Span<T> span = varray_->get_internal_span();
+ Span<T> span = varray_.get_internal_span();
return span;
}
- bool is_single_impl() const override
+ bool is_single() const override
{
- return varray_->is_single();
+ return varray_.is_single();
}
- void get_internal_single_impl(void *r_value) const override
+ void get_internal_single(void *r_value) const override
{
- *(T *)r_value = varray_->get_internal_single();
+ *(T *)r_value = varray_.get_internal_single();
}
- void set_by_copy_impl(const int64_t index, const void *value) override
+ void set_by_copy(const int64_t index, const void *value) override
{
const T &value_ = *(const T *)value;
- varray_->set(index, value_);
+ varray_.set(index, value_);
}
- void set_by_relocate_impl(const int64_t index, void *value) override
+ void set_by_relocate(const int64_t index, void *value) override
{
T &value_ = *(T *)value;
- varray_->set(index, std::move(value_));
+ varray_.set(index, std::move(value_));
value_.~T();
}
- void set_by_move_impl(const int64_t index, void *value) override
+ void set_by_move(const int64_t index, void *value) override
{
T &value_ = *(T *)value;
- varray_->set(index, std::move(value_));
+ varray_.set(index, std::move(value_));
}
- void set_all_impl(const void *src) override
+ void set_all(const void *src) override
{
- varray_->set_all(Span((T *)src, size_));
+ varray_.set_all(Span((T *)src, size_));
}
- void materialize_impl(const IndexMask mask, void *dst) const override
+ void materialize(const IndexMask mask, void *dst) const override
{
- varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
+ varray_.materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
- void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override
+ void materialize_to_uninitialized(const IndexMask mask, void *dst) const override
{
- varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
+ varray_.materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
- const void *try_get_internal_varray_impl() const override
+ bool try_assign_VArray(void *varray) const override
{
- return (const VArray<T> *)varray_;
+ *(VArray<T> *)varray = varray_;
+ return true;
}
- void *try_get_internal_mutable_varray_impl() override
+ bool try_assign_VMutableArray(void *varray) const override
{
- return varray_;
+ *(VMutableArray<T> *)varray = varray_;
+ return true;
}
-};
-
-/* 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)
+ bool may_have_ownership() const override
{
- BLI_assert(varray.type().is<T>());
- this->data_ = (const T *)varray_gspan_.data();
- this->size_ = varray_gspan_.size();
+ return varray_.may_have_ownership();
}
};
-template<typename T> class GVArray_For_OwnedVArray : public GVArray_For_VArray<T> {
- private:
- VArrayPtr<T> owned_varray_;
+/* Used to convert an generic mutable virtual array into a typed one. */
+template<typename T> class VMutableArrayImpl_For_GVMutableArray : public VMutableArrayImpl<T> {
+ protected:
+ GVMutableArray varray_;
public:
- /* 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))
+ VMutableArrayImpl_For_GVMutableArray(GVMutableArray varray)
+ : VMutableArrayImpl<T>(varray.size()), varray_(varray)
{
+ BLI_assert(varray_);
+ BLI_assert(varray_.type().is<T>());
}
-};
-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))
+ T get(const int64_t index) const override
{
+ T value;
+ varray_.get(index, &value);
+ return value;
}
-};
-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))
+ void set(const int64_t index, T value) override
{
+ varray_.set_by_relocate(index, &value);
}
-};
-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))
+ bool is_span() const override
{
+ return varray_.is_span();
}
-};
-
-/* 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)...)
+ Span<T> get_internal_span() const override
{
- this->varray_ = &embedded_varray_;
+ return varray_.get_internal_span().template typed<T>();
}
-};
-/* 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)...)
+ bool is_single() const override
{
- this->varray_ = &embedded_varray_;
+ return varray_.is_single();
}
-};
-/* 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))
+ T get_internal_single() const override
{
+ T value;
+ varray_.get_internal_single(&value);
+ return value;
}
-};
-/* 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)
+ bool try_assign_GVArray(GVArray &varray) const override
{
+ varray = varray_;
+ return true;
}
-};
-/* 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)
+ bool try_assign_GVMutableArray(GVMutableArray &varray) const override
{
+ varray = varray_;
+ return true;
}
-};
-/* 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)
+ bool may_have_ownership() const override
{
+ return varray_.may_have_ownership();
}
};
-/* 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>> {
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl_For_GSpan and #GVMutableArrayImpl_For_GMutableSpan.
+ * \{ */
+
+class GVArrayImpl_For_GSpan : public GVArrayImpl {
+ protected:
+ const void *data_ = nullptr;
+ const int64_t element_size_;
+
public:
- GVMutableArray_For_MutableSpan(const MutableSpan<T> data)
- : GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>>(data.size(),
- data)
- {
- }
+ GVArrayImpl_For_GSpan(const GSpan span);
+
+ protected:
+ GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size);
+
+ void get(const int64_t index, void *r_value) const override;
+ void get_to_uninitialized(const int64_t index, void *r_value) const override;
+
+ bool is_span() const override;
+ GSpan get_internal_span() const override;
};
-/**
- * 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_;
+class GVMutableArrayImpl_For_GMutableSpan : public GVMutableArrayImpl {
+ protected:
+ void *data_ = nullptr;
+ const int64_t element_size_;
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_;
- }
- }
+ GVMutableArrayImpl_For_GMutableSpan(const GMutableSpan span);
- /* 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);
- }
+ protected:
+ GVMutableArrayImpl_For_GMutableSpan(const CPPType &type, const int64_t size);
- const VArray<T> &operator*() const
- {
- return *varray_;
- }
+ public:
+ void get(const int64_t index, void *r_value) const override;
+ void get_to_uninitialized(const int64_t index, void *r_value) const override;
- const VArray<T> *operator->() const
- {
- return varray_;
- }
+ void set_by_copy(const int64_t index, const void *value) override;
+ void set_by_move(const int64_t index, void *value) override;
+ void set_by_relocate(const int64_t index, void *value) override;
- /* 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_;
- }
+ bool is_span() const override;
+ GSpan get_internal_span() const override;
+};
- T operator[](const int64_t index) const
- {
- return varray_->get(index);
- }
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline methods for #GVArrayImpl.
+ * \{ */
+
+inline GVArrayImpl::GVArrayImpl(const CPPType &type, const int64_t size)
+ : type_(&type), size_(size)
+{
+ BLI_assert(size_ >= 0);
+}
+
+inline const CPPType &GVArrayImpl::type() const
+{
+ return *type_;
+}
+
+inline int64_t GVArrayImpl::size() const
+{
+ return size_;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline methods for #GVMutableArrayImpl.
+ * \{ */
+
+inline void GVMutableArray::set_by_copy(const int64_t index, const void *value)
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ this->get_impl()->set_by_copy(index, value);
+}
+
+inline void GVMutableArray::set_by_move(const int64_t index, void *value)
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ this->get_impl()->set_by_move(index, value);
+}
+
+inline void GVMutableArray::set_by_relocate(const int64_t index, void *value)
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ this->get_impl()->set_by_relocate(index, value);
+}
- int64_t size() const
- {
- return varray_->size();
+template<typename T>
+inline bool GVMutableArray::try_assign_VMutableArray(VMutableArray<T> &varray) const
+{
+ BLI_assert(impl_->type().is<T>());
+ return this->get_impl()->try_assign_VMutableArray(&varray);
+}
+
+inline GVMutableArrayImpl *GVMutableArray::get_impl() const
+{
+ return (GVMutableArrayImpl *)impl_;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline methods for #GVArrayCommon.
+ * \{ */
+
+template<typename ImplT, typename... Args> inline void GVArrayCommon::emplace(Args &&...args)
+{
+ static_assert(std::is_base_of_v<GVArrayImpl, ImplT>);
+ if constexpr (std::is_copy_constructible_v<ImplT> && Storage::template is_inline_v<ImplT>) {
+ impl_ = &storage_.template emplace<ImplT>(std::forward<Args>(args)...);
+ }
+ else {
+ std::shared_ptr<const GVArrayImpl> ptr = std::make_shared<ImplT>(std::forward<Args>(args)...);
+ impl_ = &*ptr;
+ storage_ = std::move(ptr);
+ }
+}
+
+/* Copies the value at the given index into the provided storage. The `r_value` pointer is
+ * expected to point to initialized memory. */
+inline void GVArrayCommon::get(const int64_t index, void *r_value) const
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ impl_->get(index, r_value);
+}
+
+/* Same as `get`, but `r_value` is expected to point to uninitialized memory. */
+inline void GVArrayCommon::get_to_uninitialized(const int64_t index, void *r_value) const
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ impl_->get_to_uninitialized(index, r_value);
+}
+
+template<typename T> inline bool GVArrayCommon::try_assign_VArray(VArray<T> &varray) const
+{
+ BLI_assert(impl_->type().is<T>());
+ return impl_->try_assign_VArray(&varray);
+}
+
+inline const CPPType &GVArrayCommon::type() const
+{
+ return impl_->type();
+}
+
+inline GVArrayCommon::operator bool() const
+{
+ return impl_ != nullptr;
+}
+
+inline int64_t GVArrayCommon::size() const
+{
+ if (impl_ == nullptr) {
+ return 0;
+ }
+ return impl_->size();
+}
+
+inline bool GVArrayCommon::is_empty() const
+{
+ return this->size() == 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline methods for #GVArray.
+ * \{ */
+
+namespace detail {
+template<typename StorageT> inline GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get()
+{
+ static_assert(std::is_base_of_v<GVArrayImpl, StorageT> ||
+ std::is_same_v<StorageT, const GVArrayImpl *> ||
+ std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>);
+
+ if constexpr (std::is_base_of_v<GVArrayImpl, StorageT>) {
+ return {[](const void *buffer) {
+ return static_cast<const GVArrayImpl *>((const StorageT *)buffer);
+ }};
+ }
+ else if constexpr (std::is_same_v<StorageT, const GVArrayImpl *>) {
+ return {[](const void *buffer) { return *(const StorageT *)buffer; }};
+ }
+ else if constexpr (std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>) {
+ return {[](const void *buffer) { return ((const StorageT *)buffer)->get(); }};
+ }
+ else {
+ BLI_assert_unreachable();
+ return {};
+ }
+}
+} // namespace detail
+
+template<typename ImplT, typename... Args> inline GVArray GVArray::For(Args &&...args)
+{
+ static_assert(std::is_base_of_v<GVArrayImpl, ImplT>);
+ GVArray varray;
+ varray.template emplace<ImplT>(std::forward<Args>(args)...);
+ return varray;
+}
+
+template<typename T> inline GVArray::GVArray(const VArray<T> &varray)
+{
+ if (!varray) {
+ return;
+ }
+ if (varray.try_assign_GVArray(*this)) {
+ return;
+ }
+ /* Need to check this before the span/single special cases, because otherwise we might loose
+ * ownership to the referenced data when #varray goes out of scope. */
+ if (varray.may_have_ownership()) {
+ *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
+ }
+ else if (varray.is_span()) {
+ Span<T> data = varray.get_internal_span();
+ *this = GVArray::ForSpan(data);
+ }
+ else if (varray.is_single()) {
+ T value = varray.get_internal_single();
+ *this = GVArray::ForSingle(CPPType::get<T>(), varray.size(), &value);
+ }
+ else {
+ *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
+ }
+}
+
+template<typename T> inline VArray<T> GVArray::typed() const
+{
+ if (!*this) {
+ return {};
+ }
+ BLI_assert(impl_->type().is<T>());
+ VArray<T> varray;
+ if (this->try_assign_VArray(varray)) {
+ return varray;
+ }
+ if (this->may_have_ownership()) {
+ return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
+ }
+ if (this->is_span()) {
+ const Span<T> span = this->get_internal_span().typed<T>();
+ return VArray<T>::ForSpan(span);
}
-
- IndexRange index_range() const
- {
- return IndexRange(this->size());
+ if (this->is_single()) {
+ T value;
+ this->get_internal_single(&value);
+ return VArray<T>::ForSingle(value, this->size());
}
-};
+ return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
+}
-/* 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_;
- }
- }
+/* -------------------------------------------------------------------- */
+/** \name Inline methods for #GVMutableArray.
+ * \{ */
- explicit GVMutableArray_Typed(GVMutableArrayPtr gvarray) : GVMutableArray_Typed(*gvarray)
- {
- owned_gvarray_ = std::move(gvarray);
- }
+template<typename ImplT, typename... Args>
+inline GVMutableArray GVMutableArray::For(Args &&...args)
+{
+ static_assert(std::is_base_of_v<GVMutableArrayImpl, ImplT>);
+ GVMutableArray varray;
+ varray.emplace<ImplT>(std::forward<Args>(args)...);
+ return varray;
+}
- VMutableArray<T> &operator*()
- {
- return *varray_;
+template<typename T> inline GVMutableArray::GVMutableArray(const VMutableArray<T> &varray)
+{
+ if (!varray) {
+ return;
}
-
- VMutableArray<T> *operator->()
- {
- return varray_;
+ if (varray.try_assign_GVMutableArray(*this)) {
+ return;
}
-
- operator VMutableArray<T> &()
- {
- return *varray_;
+ if (varray.may_have_ownership()) {
+ *this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray);
}
-
- T operator[](const int64_t index) const
- {
- return varray_->get(index);
+ else if (varray.is_span()) {
+ MutableSpan<T> data = varray.get_internal_span();
+ *this = GVMutableArray::ForSpan(data);
}
-
- int64_t size() const
- {
- return varray_->size();
+ else {
+ *this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray);
}
-};
-
-class GVArray_For_SlicedGVArray : public GVArray {
- protected:
- const GVArray &varray_;
- int64_t offset_;
+}
- public:
- GVArray_For_SlicedGVArray(const GVArray &varray, const IndexRange slice)
- : GVArray(varray.type(), slice.size()), varray_(varray), offset_(slice.start())
- {
- BLI_assert(slice.one_after_last() <= varray.size());
+template<typename T> inline VMutableArray<T> GVMutableArray::typed() const
+{
+ if (!*this) {
+ return {};
}
-
- /* TODO: Add #materialize method. */
- 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;
-};
-
-/**
- * Utility class to create the "best" sliced virtual array.
- */
-class GVArray_Slice {
- private:
- const GVArray *varray_;
- /* Of these optional virtual arrays, at most one is constructed at any time. */
- std::optional<GVArray_For_GSpan> varray_span_;
- std::optional<GVArray_For_SlicedGVArray> varray_any_;
-
- public:
- GVArray_Slice(const GVArray &varray, const IndexRange slice);
-
- const GVArray &operator*()
- {
- return *varray_;
+ BLI_assert(this->type().is<T>());
+ VMutableArray<T> varray;
+ if (this->try_assign_VMutableArray(varray)) {
+ return varray;
}
-
- const GVArray *operator->()
- {
- return varray_;
+ if (this->may_have_ownership()) {
+ return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this);
}
-
- operator const GVArray &()
- {
- return *varray_;
+ if (this->is_span()) {
+ const MutableSpan<T> span = this->get_internal_span().typed<T>();
+ return VMutableArray<T>::ForSpan(span);
}
-};
+ return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this);
+}
+
+/** \} */
} // namespace blender::fn
diff --git a/source/blender/functions/FN_generic_virtual_vector_array.hh b/source/blender/functions/FN_generic_virtual_vector_array.hh
index 4155a55a801..b80e21eaef1 100644
--- a/source/blender/functions/FN_generic_virtual_vector_array.hh
+++ b/source/blender/functions/FN_generic_virtual_vector_array.hh
@@ -100,31 +100,31 @@ class GVVectorArray {
}
};
-class GVArray_For_GVVectorArrayIndex : public GVArray {
+class GVArray_For_GVVectorArrayIndex : public GVArrayImpl {
private:
const GVVectorArray &vector_array_;
const int64_t index_;
public:
GVArray_For_GVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index)
- : GVArray(vector_array.type(), vector_array.get_vector_size(index)),
+ : GVArrayImpl(vector_array.type(), vector_array.get_vector_size(index)),
vector_array_(vector_array),
index_(index)
{
}
protected:
- void get_impl(const int64_t index_in_vector, void *r_value) const override;
- void get_to_uninitialized_impl(const int64_t index_in_vector, void *r_value) const override;
+ void get(const int64_t index_in_vector, void *r_value) const override;
+ void get_to_uninitialized(const int64_t index_in_vector, void *r_value) const override;
};
class GVVectorArray_For_SingleGVArray : public GVVectorArray {
private:
- const GVArray &array_;
+ GVArray varray_;
public:
- GVVectorArray_For_SingleGVArray(const GVArray &array, const int64_t size)
- : GVVectorArray(array.type(), size), array_(array)
+ GVVectorArray_For_SingleGVArray(GVArray varray, const int64_t size)
+ : GVVectorArray(varray.type(), size), varray_(std::move(varray))
{
}
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh
index d187985de9d..5c7e75230f3 100644
--- a/source/blender/functions/FN_multi_function_params.hh
+++ b/source/blender/functions/FN_multi_function_params.hh
@@ -40,7 +40,7 @@ class MFParamsBuilder {
const MFSignature *signature_;
IndexMask mask_;
int64_t min_array_size_;
- Vector<const GVArray *> virtual_arrays_;
+ Vector<GVArray> virtual_arrays_;
Vector<GMutableSpan> mutable_spans_;
Vector<const GVVectorArray *> virtual_vector_arrays_;
Vector<GVectorArray *> vector_arrays_;
@@ -68,24 +68,22 @@ class MFParamsBuilder {
template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "")
{
this->add_readonly_single_input(
- scope_.construct<GVArray_For_SingleValueRef>(CPPType::get<T>(), min_array_size_, value),
- expected_name);
+ GVArray::ForSingleRef(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<GVArray_For_GSpan>(span), expected_name);
+ this->add_readonly_single_input(GVArray::ForSpan(span), expected_name);
}
void add_readonly_single_input(GPointer value, StringRef expected_name = "")
{
this->add_readonly_single_input(
- scope_.construct<GVArray_For_SingleValueRef>(*value.type(), min_array_size_, value.get()),
- expected_name);
+ GVArray::ForSingleRef(*value.type(), min_array_size_, value.get()), expected_name);
}
- void add_readonly_single_input(const GVArray &ref, StringRef expected_name = "")
+ void add_readonly_single_input(GVArray varray, StringRef expected_name = "")
{
- this->assert_current_param_type(MFParamType::ForSingleInput(ref.type()), expected_name);
- BLI_assert(ref.size() >= min_array_size_);
- virtual_arrays_.append(&ref);
+ this->assert_current_param_type(MFParamType::ForSingleInput(varray.type()), expected_name);
+ BLI_assert(varray.size() >= min_array_size_);
+ virtual_arrays_.append(varray);
}
void add_readonly_vector_input(const GVectorArray &vector_array, StringRef expected_name = "")
@@ -221,16 +219,16 @@ class MFParams {
{
}
- template<typename T> const VArray<T> &readonly_single_input(int param_index, StringRef name = "")
+ template<typename T> VArray<T> readonly_single_input(int param_index, StringRef name = "")
{
- const GVArray &array = this->readonly_single_input(param_index, name);
- return builder_->scope_.construct<GVArray_Typed<T>>(array);
+ const GVArray &varray = this->readonly_single_input(param_index, name);
+ return varray.typed<T>();
}
const GVArray &readonly_single_input(int param_index, StringRef name = "")
{
this->assert_correct_param(param_index, name, MFParamType::SingleInput);
int data_index = builder_->signature_->data_index(param_index);
- return *builder_->virtual_arrays_[data_index];
+ return builder_->virtual_arrays_[data_index];
}
/**
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index 4de5e71c910..68a8446e6ae 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -81,19 +81,18 @@ static FieldTreeInfo preprocess_field_tree(Span<GFieldRef> entry_fields)
/**
* Retrieves the data from the context that is passed as input into the field.
*/
-static Vector<const GVArray *> get_field_context_inputs(
+static Vector<GVArray> get_field_context_inputs(
ResourceScope &scope,
const IndexMask mask,
const FieldContext &context,
const Span<std::reference_wrapper<const FieldInput>> field_inputs)
{
- Vector<const GVArray *> field_context_inputs;
+ Vector<GVArray> field_context_inputs;
for (const FieldInput &field_input : field_inputs) {
- const GVArray *varray = context.get_varray_for_input(field_input, mask, scope);
- if (varray == nullptr) {
+ GVArray varray = context.get_varray_for_input(field_input, mask, scope);
+ if (!varray) {
const CPPType &type = field_input.cpp_type();
- varray = &scope.construct<GVArray_For_SingleValueRef>(
- type, mask.min_array_size(), type.default_value());
+ varray = GVArray::ForSingleDefault(type, mask.min_array_size());
}
field_context_inputs.append(varray);
}
@@ -105,7 +104,7 @@ static Vector<const GVArray *> get_field_context_inputs(
* for different indices.
*/
static Set<GFieldRef> find_varying_fields(const FieldTreeInfo &field_tree_info,
- Span<const GVArray *> field_context_inputs)
+ Span<GVArray> field_context_inputs)
{
Set<GFieldRef> found_fields;
Stack<GFieldRef> fields_to_check;
@@ -114,8 +113,8 @@ static Set<GFieldRef> find_varying_fields(const FieldTreeInfo &field_tree_info,
* start the tree search at the non-constant input fields and traverse through all fields that
* depend on them. */
for (const int i : field_context_inputs.index_range()) {
- const GVArray *varray = field_context_inputs[i];
- if (varray->is_single()) {
+ const GVArray &varray = field_context_inputs[i];
+ if (varray.is_single()) {
continue;
}
const FieldInput &field_input = field_tree_info.deduplicated_field_inputs[i];
@@ -278,29 +277,42 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure,
* \return The computed virtual arrays for each provided field. If #dst_varrays is passed, the
* provided virtual arrays are returned.
*/
-Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
- Span<GFieldRef> fields_to_evaluate,
- IndexMask mask,
- const FieldContext &context,
- Span<GVMutableArray *> dst_varrays)
+Vector<GVArray> evaluate_fields(ResourceScope &scope,
+ Span<GFieldRef> fields_to_evaluate,
+ IndexMask mask,
+ const FieldContext &context,
+ Span<GVMutableArray> dst_varrays)
{
- Vector<const GVArray *> r_varrays(fields_to_evaluate.size(), nullptr);
+ Vector<GVArray> r_varrays(fields_to_evaluate.size());
+ Array<bool> is_output_written_to_dst(fields_to_evaluate.size(), false);
const int array_size = mask.min_array_size();
+ if (mask.is_empty()) {
+ for (const int i : fields_to_evaluate.index_range()) {
+ const CPPType &type = fields_to_evaluate[i].cpp_type();
+ r_varrays[i] = GVArray::ForEmpty(type);
+ }
+ return r_varrays;
+ }
+
/* Destination arrays are optional. Create a small utility method to access them. */
- auto get_dst_varray_if_available = [&](int index) -> GVMutableArray * {
+ auto get_dst_varray = [&](int index) -> GVMutableArray {
if (dst_varrays.is_empty()) {
- return nullptr;
+ return {};
+ }
+ const GVMutableArray &varray = dst_varrays[index];
+ if (!varray) {
+ return {};
}
- BLI_assert(dst_varrays[index] == nullptr || dst_varrays[index]->size() >= array_size);
- return dst_varrays[index];
+ BLI_assert(varray.size() >= array_size);
+ return varray;
};
/* Traverse the field tree and prepare some data that is used in later steps. */
FieldTreeInfo field_tree_info = preprocess_field_tree(fields_to_evaluate);
/* Get inputs that will be passed into the field when evaluated. */
- Vector<const GVArray *> field_context_inputs = get_field_context_inputs(
+ Vector<GVArray> field_context_inputs = get_field_context_inputs(
scope, mask, context, field_tree_info.deduplicated_field_inputs);
/* Finish fields that output an input varray directly. For those we don't have to do any further
@@ -312,7 +324,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
}
const FieldInput &field_input = static_cast<const FieldInput &>(field.node());
const int field_input_index = field_tree_info.deduplicated_field_inputs.index_of(field_input);
- const GVArray *varray = field_context_inputs[field_input_index];
+ const GVArray &varray = field_context_inputs[field_input_index];
r_varrays[out_index] = varray;
}
@@ -325,7 +337,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
Vector<GFieldRef> constant_fields_to_evaluate;
Vector<int> constant_field_indices;
for (const int i : fields_to_evaluate.index_range()) {
- if (r_varrays[i] != nullptr) {
+ if (r_varrays[i]) {
/* Already done. */
continue;
}
@@ -357,8 +369,8 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
MFContextBuilder mf_context;
/* Provide inputs to the procedure executor. */
- for (const GVArray *varray : field_context_inputs) {
- mf_params.add_readonly_single_input(*varray);
+ for (const GVArray &varray : field_context_inputs) {
+ mf_params.add_readonly_single_input(varray);
}
for (const int i : varying_fields_to_evaluate.index_range()) {
@@ -367,9 +379,9 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
const int out_index = varying_field_indices[i];
/* Try to get an existing virtual array that the result should be written into. */
- GVMutableArray *output_varray = get_dst_varray_if_available(out_index);
+ GVMutableArray dst_varray = get_dst_varray(out_index);
void *buffer;
- if (output_varray == nullptr || !output_varray->is_span()) {
+ if (!dst_varray || !dst_varray.is_span()) {
/* Allocate a new buffer for the computed result. */
buffer = scope.linear_allocator().allocate(type.size() * array_size, type.alignment());
@@ -379,14 +391,14 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
[buffer, mask, &type]() { type.destruct_indices(buffer, mask); });
}
- r_varrays[out_index] = &scope.construct<GVArray_For_GSpan>(
- GSpan{type, buffer, array_size});
+ r_varrays[out_index] = GVArray::ForSpan({type, buffer, array_size});
}
else {
/* Write the result into the existing span. */
- buffer = output_varray->get_internal_span().data();
+ buffer = dst_varray.get_internal_span().data();
- r_varrays[out_index] = output_varray;
+ r_varrays[out_index] = dst_varray;
+ is_output_written_to_dst[out_index] = true;
}
/* Pass output buffer to the procedure executor. */
@@ -404,15 +416,12 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
build_multi_function_procedure_for_fields(
procedure, scope, field_tree_info, constant_fields_to_evaluate);
MFProcedureExecutor procedure_executor{"Procedure", procedure};
- /* Run the code below even when the mask is empty, so that outputs are properly prepared.
- * Higher level code can detect this as well and just skip evaluating the field. */
- const int mask_size = mask.is_empty() ? 0 : 1;
- MFParamsBuilder mf_params{procedure_executor, mask_size};
+ MFParamsBuilder mf_params{procedure_executor, 1};
MFContextBuilder mf_context;
/* Provide inputs to the procedure executor. */
- for (const GVArray *varray : field_context_inputs) {
- mf_params.add_readonly_single_input(*varray);
+ for (const GVArray &varray : field_context_inputs) {
+ mf_params.add_readonly_single_input(varray);
}
for (const int i : constant_fields_to_evaluate.index_range()) {
@@ -421,55 +430,52 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
/* Allocate memory where the computed value will be stored in. */
void *buffer = scope.linear_allocator().allocate(type.size(), type.alignment());
- if (!type.is_trivially_destructible() && mask_size > 0) {
- BLI_assert(mask_size == 1);
+ if (!type.is_trivially_destructible()) {
/* Destruct value in the end. */
scope.add_destruct_call([buffer, &type]() { type.destruct(buffer); });
}
/* Pass output buffer to the procedure executor. */
- mf_params.add_uninitialized_single_output({type, buffer, mask_size});
+ mf_params.add_uninitialized_single_output({type, buffer, 1});
/* Create virtual array that can be used after the procedure has been executed below. */
const int out_index = constant_field_indices[i];
- r_varrays[out_index] = &scope.construct<GVArray_For_SingleValueRef>(
- type, array_size, buffer);
+ r_varrays[out_index] = GVArray::ForSingleRef(type, array_size, buffer);
}
- procedure_executor.call(IndexRange(mask_size), mf_params, mf_context);
+ procedure_executor.call(IndexRange(1), mf_params, mf_context);
}
- /* Copy data to supplied destination arrays if necessary. In some cases the evaluation above has
- * written the computed data in the right place already. */
+ /* Copy data to supplied destination arrays if necessary. In some cases the evaluation above
+ * has written the computed data in the right place already. */
if (!dst_varrays.is_empty()) {
for (const int out_index : fields_to_evaluate.index_range()) {
- GVMutableArray *output_varray = get_dst_varray_if_available(out_index);
- if (output_varray == nullptr) {
+ GVMutableArray dst_varray = get_dst_varray(out_index);
+ if (!dst_varray) {
/* Caller did not provide a destination for this output. */
continue;
}
- const GVArray *computed_varray = r_varrays[out_index];
- BLI_assert(computed_varray->type() == output_varray->type());
- if (output_varray == computed_varray) {
+ const GVArray &computed_varray = r_varrays[out_index];
+ BLI_assert(computed_varray.type() == dst_varray.type());
+ if (is_output_written_to_dst[out_index]) {
/* The result has been written into the destination provided by the caller already. */
continue;
}
/* Still have to copy over the data in the destination provided by the caller. */
- if (output_varray->is_span()) {
+ if (dst_varray.is_span()) {
/* Materialize into a span. */
- computed_varray->materialize_to_uninitialized(mask,
- output_varray->get_internal_span().data());
+ computed_varray.materialize_to_uninitialized(mask, dst_varray.get_internal_span().data());
}
else {
/* Slower materialize into a different structure. */
- const CPPType &type = computed_varray->type();
+ const CPPType &type = computed_varray.type();
BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
for (const int i : mask) {
- computed_varray->get_to_uninitialized(i, buffer);
- output_varray->set_by_relocate(i, buffer);
+ computed_varray.get_to_uninitialized(i, buffer);
+ dst_varray.set_by_relocate(i, buffer);
}
}
- r_varrays[out_index] = output_varray;
+ r_varrays[out_index] = dst_varray;
}
}
return r_varrays;
@@ -485,8 +491,8 @@ void evaluate_constant_field(const GField &field, void *r_value)
ResourceScope scope;
FieldContext context;
- Vector<const GVArray *> varrays = evaluate_fields(scope, {field}, IndexRange(1), context);
- varrays[0]->get_to_uninitialized(0, r_value);
+ Vector<GVArray> varrays = evaluate_fields(scope, {field}, IndexRange(1), context);
+ varrays[0].get_to_uninitialized(0, r_value);
}
/**
@@ -512,9 +518,9 @@ GField make_field_constant_if_possible(GField field)
return GField{operation, 0};
}
-const GVArray *FieldContext::get_varray_for_input(const FieldInput &field_input,
- IndexMask mask,
- ResourceScope &scope) const
+GVArray FieldContext::get_varray_for_input(const FieldInput &field_input,
+ IndexMask mask,
+ ResourceScope &scope) const
{
/* By default ask the field input to create the varray. Another field context might overwrite
* the context here. */
@@ -526,17 +532,15 @@ IndexFieldInput::IndexFieldInput() : FieldInput(CPPType::get<int>(), "Index")
category_ = Category::Generated;
}
-GVArray *IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &scope)
+GVArray IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &UNUSED(scope))
{
auto index_func = [](int i) { return i; };
- return &scope.construct<
- fn::GVArray_For_EmbeddedVArray<int, VArray_For_Func<int, decltype(index_func)>>>(
- mask.min_array_size(), mask.min_array_size(), index_func);
+ return VArray<int>::ForFunc(mask.min_array_size(), index_func);
}
-const GVArray *IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context),
- IndexMask mask,
- ResourceScope &scope) const
+GVArray IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context),
+ IndexMask mask,
+ ResourceScope &scope) const
{
/* TODO: Investigate a similar method to IndexRange::as_span() */
return get_index_varray(mask, scope);
@@ -631,27 +635,26 @@ static Vector<int64_t> indices_from_selection(const VArray<bool> &selection)
return indices;
}
-int FieldEvaluator::add_with_destination(GField field, GVMutableArray &dst)
+int FieldEvaluator::add_with_destination(GField field, GVMutableArray dst)
{
const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
- dst_varrays_.append(&dst);
+ dst_varrays_.append(dst);
output_pointer_infos_.append({});
return field_index;
}
int FieldEvaluator::add_with_destination(GField field, GMutableSpan dst)
{
- GVMutableArray &varray = scope_.construct<GVMutableArray_For_GMutableSpan>(dst);
- return this->add_with_destination(std::move(field), varray);
+ return this->add_with_destination(std::move(field), GVMutableArray::ForSpan(dst));
}
-int FieldEvaluator::add(GField field, const GVArray **varray_ptr)
+int FieldEvaluator::add(GField field, GVArray *varray_ptr)
{
const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
dst_varrays_.append(nullptr);
output_pointer_infos_.append(OutputPointerInfo{
varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &UNUSED(scope)) {
- *(const GVArray **)dst = &varray;
+ *(GVArray *)dst = varray;
}});
return field_index;
}
@@ -676,7 +679,7 @@ void FieldEvaluator::evaluate()
for (const int i : fields_to_evaluate_.index_range()) {
OutputPointerInfo &info = output_pointer_infos_[i];
if (info.dst != nullptr) {
- info.set(info.dst, *evaluated_varrays_[i], scope_);
+ info.set(info.dst, evaluated_varrays_[i], scope_);
}
}
is_evaluated_ = true;
@@ -684,17 +687,16 @@ void FieldEvaluator::evaluate()
IndexMask FieldEvaluator::get_evaluated_as_mask(const int field_index)
{
- const GVArray &varray = this->get_evaluated(field_index);
- GVArray_Typed<bool> typed_varray{varray};
+ VArray<bool> varray = this->get_evaluated(field_index).typed<bool>();
- if (typed_varray->is_single()) {
- if (typed_varray->get_internal_single()) {
- return IndexRange(typed_varray.size());
+ if (varray.is_single()) {
+ if (varray.get_internal_single()) {
+ return IndexRange(varray.size());
}
return IndexRange(0);
}
- return scope_.add_value(indices_from_selection(*typed_varray)).as_span();
+ return scope_.add_value(indices_from_selection(varray)).as_span();
}
} // namespace blender::fn
diff --git a/source/blender/functions/intern/generic_vector_array.cc b/source/blender/functions/intern/generic_vector_array.cc
index ec95a283919..0d478007a5a 100644
--- a/source/blender/functions/intern/generic_vector_array.cc
+++ b/source/blender/functions/intern/generic_vector_array.cc
@@ -60,15 +60,14 @@ void GVectorArray::extend(const int64_t index, const GVArray &values)
void GVectorArray::extend(const int64_t index, const GSpan values)
{
- GVArray_For_GSpan varray{values};
- this->extend(index, varray);
+ this->extend(index, GVArray::ForSpan(values));
}
void GVectorArray::extend(IndexMask mask, const GVVectorArray &values)
{
for (const int i : mask) {
GVArray_For_GVVectorArrayIndex array{values, i};
- this->extend(i, array);
+ this->extend(i, GVArray(&array));
}
}
diff --git a/source/blender/functions/intern/generic_virtual_array.cc b/source/blender/functions/intern/generic_virtual_array.cc
index ea54f1e7c00..1fe1c2fc229 100644
--- a/source/blender/functions/intern/generic_virtual_array.cc
+++ b/source/blender/functions/intern/generic_virtual_array.cc
@@ -19,52 +19,10 @@
namespace blender::fn {
/* -------------------------------------------------------------------- */
-/** \name #GVArray_For_ShallowCopy
+/** \name #GVArrayImpl
* \{ */
-class GVArray_For_ShallowCopy : public GVArray {
- private:
- const GVArray &varray_;
-
- public:
- GVArray_For_ShallowCopy(const GVArray &varray)
- : GVArray(varray.type(), varray.size()), varray_(varray)
- {
- }
-
- private:
- void get_impl(const int64_t index, void *r_value) const override
- {
- varray_.get(index, r_value);
- }
-
- void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
- {
- varray_.get_to_uninitialized(index, r_value);
- }
-
- void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override
- {
- varray_.materialize_to_uninitialized(mask, dst);
- }
-};
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name #GVArray
- * \{ */
-
-void GVArray::materialize(void *dst) const
-{
- this->materialize(IndexMask(size_), dst);
-}
-
-void GVArray::materialize(const IndexMask mask, void *dst) const
-{
- this->materialize_impl(mask, dst);
-}
-
-void GVArray::materialize_impl(const IndexMask mask, void *dst) const
+void GVArrayImpl::materialize(const IndexMask mask, void *dst) const
{
for (const int64_t i : mask) {
void *elem_dst = POINTER_OFFSET(dst, type_->size() * i);
@@ -72,18 +30,7 @@ void GVArray::materialize_impl(const IndexMask mask, void *dst) const
}
}
-void GVArray::materialize_to_uninitialized(void *dst) const
-{
- this->materialize_to_uninitialized(IndexMask(size_), dst);
-}
-
-void GVArray::materialize_to_uninitialized(const IndexMask mask, void *dst) const
-{
- BLI_assert(mask.min_array_size() <= size_);
- this->materialize_to_uninitialized_impl(mask, dst);
-}
-
-void GVArray::materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const
+void GVArrayImpl::materialize_to_uninitialized(const IndexMask mask, void *dst) const
{
for (const int64_t i : mask) {
void *elem_dst = POINTER_OFFSET(dst, type_->size() * i);
@@ -91,83 +38,75 @@ void GVArray::materialize_to_uninitialized_impl(const IndexMask mask, void *dst)
}
}
-void GVArray::get_impl(const int64_t index, void *r_value) const
+void GVArrayImpl::get(const int64_t index, void *r_value) const
{
type_->destruct(r_value);
- this->get_to_uninitialized_impl(index, r_value);
+ this->get_to_uninitialized(index, r_value);
}
-bool GVArray::is_span_impl() const
+bool GVArrayImpl::is_span() const
{
return false;
}
-GSpan GVArray::get_internal_span_impl() const
+GSpan GVArrayImpl::get_internal_span() const
{
BLI_assert(false);
return GSpan(*type_);
}
-bool GVArray::is_single_impl() const
+bool GVArrayImpl::is_single() const
{
return false;
}
-void GVArray::get_internal_single_impl(void *UNUSED(r_value)) const
+void GVArrayImpl::get_internal_single(void *UNUSED(r_value)) const
{
BLI_assert(false);
}
-const void *GVArray::try_get_internal_varray_impl() const
+bool GVArrayImpl::try_assign_VArray(void *UNUSED(varray)) const
{
- return nullptr;
+ return false;
}
-/**
- * Creates a new `std::unique_ptr<GVArray>` based on this `GVArray`.
- * The lifetime of the returned virtual array must not be longer than the lifetime of this virtual
- * array.
- */
-GVArrayPtr GVArray::shallow_copy() const
+bool GVArrayImpl::may_have_ownership() const
{
- if (this->is_span()) {
- return std::make_unique<GVArray_For_GSpan>(this->get_internal_span());
- }
- if (this->is_single()) {
- BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer);
- this->get_internal_single(buffer);
- std::unique_ptr new_varray = std::make_unique<GVArray_For_SingleValue>(*type_, size_, buffer);
- type_->destruct(buffer);
- return new_varray;
- }
- return std::make_unique<GVArray_For_ShallowCopy>(*this);
+ /* Use true as default to avoid accidentally creating subclasses that have this set to false but
+ * actually own data. Subclasses should set the to false instead. */
+ return true;
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #GVMutableArray
+/** \name #GVMutableArrayImpl
* \{ */
-void GVMutableArray::set_by_copy_impl(const int64_t index, const void *value)
+GVMutableArrayImpl::GVMutableArrayImpl(const CPPType &type, const int64_t size)
+ : GVArrayImpl(type, size)
+{
+}
+
+void GVMutableArrayImpl::set_by_copy(const int64_t index, const void *value)
{
BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer);
type_->copy_construct(value, buffer);
- this->set_by_move_impl(index, buffer);
+ this->set_by_move(index, buffer);
type_->destruct(buffer);
}
-void GVMutableArray::set_by_relocate_impl(const int64_t index, void *value)
+void GVMutableArrayImpl::set_by_relocate(const int64_t index, void *value)
{
- this->set_by_move_impl(index, value);
+ this->set_by_move(index, value);
type_->destruct(value);
}
-void GVMutableArray::set_all_impl(const void *src)
+void GVMutableArrayImpl::set_all(const void *src)
{
if (this->is_span()) {
- const GMutableSpan span = this->get_internal_span();
- type_->copy_assign_n(src, span.data(), size_);
+ const GSpan span = this->get_internal_span();
+ type_->copy_assign_n(src, const_cast<void *>(span.data()), size_);
}
else {
for (int64_t i : IndexRange(size_)) {
@@ -176,149 +115,224 @@ void GVMutableArray::set_all_impl(const void *src)
}
}
-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_assign_n(value, span.data(), size_);
+ const GSpan span = this->get_internal_span();
+ this->type().fill_assign_n(value, const_cast<void *>(span.data()), this->size());
}
else {
- for (int64_t i : IndexRange(size_)) {
+ for (int64_t i : IndexRange(this->size())) {
this->set_by_copy(i, value);
}
}
}
+bool GVMutableArrayImpl::try_assign_VMutableArray(void *UNUSED(varray)) const
+{
+ return false;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #GVArray_For_GSpan
+/** \name #GVArrayImpl_For_GSpan
* \{ */
-void GVArray_For_GSpan::get_impl(const int64_t index, void *r_value) const
+GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const GSpan span)
+ : GVArrayImpl(span.type(), span.size()), data_(span.data()), element_size_(span.type().size())
+{
+}
+
+GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size)
+ : GVArrayImpl(type, size), element_size_(type.size())
+{
+}
+
+void GVArrayImpl_For_GSpan::get(const int64_t index, void *r_value) const
{
type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-void GVArray_For_GSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const
+void GVArrayImpl_For_GSpan::get_to_uninitialized(const int64_t index, void *r_value) const
{
type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-bool GVArray_For_GSpan::is_span_impl() const
+bool GVArrayImpl_For_GSpan::is_span() const
{
return true;
}
-GSpan GVArray_For_GSpan::get_internal_span_impl() const
+GSpan GVArrayImpl_For_GSpan::get_internal_span() const
{
return GSpan(*type_, data_, size_);
}
+/** See #VArrayImpl_For_Span_final. */
+class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
+ public:
+ using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan;
+
+ private:
+ bool may_have_ownership() const override
+ {
+ return false;
+ }
+};
+
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #GVMutableArray_For_GMutableSpan
+/** \name #GVMutableArrayImpl_For_GMutableSpan
* \{ */
-void GVMutableArray_For_GMutableSpan::get_impl(const int64_t index, void *r_value) const
+GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan(const GMutableSpan span)
+ : GVMutableArrayImpl(span.type(), span.size()),
+ data_(span.data()),
+ element_size_(span.type().size())
+{
+}
+
+GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan(const CPPType &type,
+ const int64_t size)
+ : GVMutableArrayImpl(type, size), element_size_(type.size())
+{
+}
+
+void GVMutableArrayImpl_For_GMutableSpan::get(const int64_t index, void *r_value) const
{
type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-void GVMutableArray_For_GMutableSpan::get_to_uninitialized_impl(const int64_t index,
- void *r_value) const
+void GVMutableArrayImpl_For_GMutableSpan::get_to_uninitialized(const int64_t index,
+ void *r_value) const
{
type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-void GVMutableArray_For_GMutableSpan::set_by_copy_impl(const int64_t index, const void *value)
+void GVMutableArrayImpl_For_GMutableSpan::set_by_copy(const int64_t index, const void *value)
{
type_->copy_assign(value, POINTER_OFFSET(data_, element_size_ * index));
}
-void GVMutableArray_For_GMutableSpan::set_by_move_impl(const int64_t index, void *value)
+void GVMutableArrayImpl_For_GMutableSpan::set_by_move(const int64_t index, void *value)
{
type_->move_construct(value, POINTER_OFFSET(data_, element_size_ * index));
}
-void GVMutableArray_For_GMutableSpan::set_by_relocate_impl(const int64_t index, void *value)
+void GVMutableArrayImpl_For_GMutableSpan::set_by_relocate(const int64_t index, void *value)
{
type_->relocate_assign(value, POINTER_OFFSET(data_, element_size_ * index));
}
-bool GVMutableArray_For_GMutableSpan::is_span_impl() const
+bool GVMutableArrayImpl_For_GMutableSpan::is_span() const
{
return true;
}
-GSpan GVMutableArray_For_GMutableSpan::get_internal_span_impl() const
+GSpan GVMutableArrayImpl_For_GMutableSpan::get_internal_span() const
{
return GSpan(*type_, data_, size_);
}
+class GVMutableArrayImpl_For_GMutableSpan_final final
+ : public GVMutableArrayImpl_For_GMutableSpan {
+ public:
+ using GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan;
+
+ private:
+ bool may_have_ownership() const override
+ {
+ return false;
+ }
+};
+
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #GVArray_For_SingleValueRef
+/** \name #GVArrayImpl_For_SingleValueRef
* \{ */
-void GVArray_For_SingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const
-{
- type_->copy_assign(value_, r_value);
-}
+/* Generic virtual array where each element has the same value. The value is not owned. */
+class GVArrayImpl_For_SingleValueRef : public GVArrayImpl {
+ protected:
+ const void *value_ = nullptr;
-void GVArray_For_SingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index),
- void *r_value) const
-{
- type_->copy_construct(value_, r_value);
-}
+ public:
+ GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
+ : GVArrayImpl(type, size), value_(value)
+ {
+ }
-bool GVArray_For_SingleValueRef::is_span_impl() const
-{
- return size_ == 1;
-}
+ protected:
+ GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArrayImpl(type, size)
+ {
+ }
-GSpan GVArray_For_SingleValueRef::get_internal_span_impl() const
-{
- return GSpan{*type_, value_, 1};
-}
+ void get(const int64_t UNUSED(index), void *r_value) const override
+ {
+ type_->copy_assign(value_, r_value);
+ }
+ void get_to_uninitialized(const int64_t UNUSED(index), void *r_value) const override
+ {
+ type_->copy_construct(value_, r_value);
+ }
-bool GVArray_For_SingleValueRef::is_single_impl() const
-{
- return true;
-}
+ bool is_span() const override
+ {
+ return size_ == 1;
+ }
+ GSpan get_internal_span() const override
+ {
+ return GSpan{*type_, value_, 1};
+ }
-void GVArray_For_SingleValueRef::get_internal_single_impl(void *r_value) const
-{
- type_->copy_assign(value_, r_value);
-}
+ bool is_single() const override
+ {
+ return true;
+ }
+ void get_internal_single(void *r_value) const override
+ {
+ type_->copy_assign(value_, r_value);
+ }
+};
+
+class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_SingleValueRef {
+ public:
+ using GVArrayImpl_For_SingleValueRef::GVArrayImpl_For_SingleValueRef;
+
+ private:
+ bool may_have_ownership() const override
+ {
+ return false;
+ }
+};
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #GVArray_For_SingleValue
+/** \name #GVArrayImpl_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_construct(value, (void *)value_);
-}
+/* Same as GVArrayImpl_For_SingleValueRef, but the value is owned. */
+class GVArrayImpl_For_SingleValue : public GVArrayImpl_For_SingleValueRef,
+ NonCopyable,
+ NonMovable {
+ public:
+ GVArrayImpl_For_SingleValue(const CPPType &type, const int64_t size, const void *value)
+ : GVArrayImpl_For_SingleValueRef(type, size)
+ {
+ value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
+ type.copy_construct(value, (void *)value_);
+ }
-GVArray_For_SingleValue::~GVArray_For_SingleValue()
-{
- type_->destruct((void *)value_);
- MEM_freeN((void *)value_);
-}
+ ~GVArrayImpl_For_SingleValue() override
+ {
+ type_->destruct((void *)value_);
+ MEM_freeN((void *)value_);
+ }
+};
/** \} */
@@ -326,7 +340,7 @@ GVArray_For_SingleValue::~GVArray_For_SingleValue()
/** \name #GVArray_GSpan
* \{ */
-GVArray_GSpan::GVArray_GSpan(const GVArray &varray) : GSpan(varray.type()), varray_(varray)
+GVArray_GSpan::GVArray_GSpan(GVArray varray) : GSpan(varray.type()), varray_(std::move(varray))
{
size_ = varray_.size();
if (varray_.is_span()) {
@@ -353,8 +367,8 @@ GVArray_GSpan::~GVArray_GSpan()
/** \name #GVMutableArray_GSpan
* \{ */
-GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray &varray, const bool copy_values_to_span)
- : GMutableSpan(varray.type()), varray_(varray)
+GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray varray, const bool copy_values_to_span)
+ : GMutableSpan(varray.type()), varray_(std::move(varray))
{
size_ = varray_.size();
if (varray_.is_span()) {
@@ -405,48 +419,314 @@ void GVMutableArray_GSpan::disable_not_applied_warning()
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #GVArray_For_SlicedGVArray
+/** \name #GVArrayImpl_For_SlicedGVArray
* \{ */
-void GVArray_For_SlicedGVArray::get_impl(const int64_t index, void *r_value) const
+class GVArrayImpl_For_SlicedGVArray : public GVArrayImpl {
+ protected:
+ GVArray varray_;
+ int64_t offset_;
+
+ public:
+ GVArrayImpl_For_SlicedGVArray(GVArray varray, const IndexRange slice)
+ : GVArrayImpl(varray.type(), slice.size()),
+ varray_(std::move(varray)),
+ offset_(slice.start())
+ {
+ BLI_assert(slice.one_after_last() <= varray_.size());
+ }
+
+ void get(const int64_t index, void *r_value) const override
+ {
+ varray_.get(index + offset_, r_value);
+ }
+
+ void get_to_uninitialized(const int64_t index, void *r_value) const override
+ {
+ varray_.get_to_uninitialized(index + offset_, r_value);
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayCommon
+ * \{ */
+
+GVArrayCommon::GVArrayCommon() = default;
+
+GVArrayCommon::GVArrayCommon(const GVArrayCommon &other) : storage_(other.storage_)
+{
+ impl_ = this->impl_from_storage();
+}
+
+GVArrayCommon::GVArrayCommon(GVArrayCommon &&other) noexcept : storage_(std::move(other.storage_))
+{
+ impl_ = this->impl_from_storage();
+ other.storage_.reset();
+ other.impl_ = nullptr;
+}
+
+GVArrayCommon::GVArrayCommon(const GVArrayImpl *impl) : impl_(impl)
+{
+ storage_ = impl_;
+}
+
+GVArrayCommon::GVArrayCommon(std::shared_ptr<const GVArrayImpl> impl) : impl_(impl.get())
+{
+ if (impl) {
+ storage_ = std::move(impl);
+ }
+}
+
+GVArrayCommon::~GVArrayCommon() = default;
+
+void GVArrayCommon::materialize(void *dst) const
+{
+ this->materialize(IndexMask(impl_->size()), dst);
+}
+
+void GVArrayCommon::materialize(const IndexMask mask, void *dst) const
+{
+ impl_->materialize(mask, dst);
+}
+
+void GVArrayCommon::materialize_to_uninitialized(void *dst) const
+{
+ this->materialize_to_uninitialized(IndexMask(impl_->size()), dst);
+}
+
+void GVArrayCommon::materialize_to_uninitialized(const IndexMask mask, void *dst) const
+{
+ BLI_assert(mask.min_array_size() <= impl_->size());
+ impl_->materialize_to_uninitialized(mask, dst);
+}
+
+bool GVArrayCommon::may_have_ownership() const
+{
+ return impl_->may_have_ownership();
+}
+
+void GVArrayCommon::copy_from(const GVArrayCommon &other)
+{
+ if (this == &other) {
+ return;
+ }
+ storage_ = other.storage_;
+ impl_ = this->impl_from_storage();
+}
+
+void GVArrayCommon::move_from(GVArrayCommon &&other) noexcept
+{
+ if (this == &other) {
+ return;
+ }
+ storage_ = std::move(other.storage_);
+ impl_ = this->impl_from_storage();
+ other.storage_.reset();
+ other.impl_ = nullptr;
+}
+
+/* Returns true when the virtual array is stored as a span internally. */
+bool GVArrayCommon::is_span() const
+{
+ if (this->is_empty()) {
+ return true;
+ }
+ return impl_->is_span();
+}
+
+/* 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 GVArrayCommon::get_internal_span() const
{
- varray_.get(index + offset_, r_value);
+ BLI_assert(this->is_span());
+ if (this->is_empty()) {
+ return GSpan(impl_->type());
+ }
+ return impl_->get_internal_span();
}
-void GVArray_For_SlicedGVArray::get_to_uninitialized_impl(const int64_t index, void *r_value) const
+/* Returns true when the virtual array returns the same value for every index. */
+bool GVArrayCommon::is_single() const
{
- varray_.get_to_uninitialized(index + offset_, r_value);
+ if (impl_->size() == 1) {
+ return true;
+ }
+ return impl_->is_single();
+}
+
+/* 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 GVArrayCommon::get_internal_single(void *r_value) const
+{
+ BLI_assert(this->is_single());
+ if (impl_->size() == 1) {
+ impl_->get(0, r_value);
+ return;
+ }
+ impl_->get_internal_single(r_value);
+}
+
+/* Same as `get_internal_single`, but `r_value` points to initialized memory. */
+void GVArrayCommon::get_internal_single_to_uninitialized(void *r_value) const
+{
+ impl_->type().default_construct(r_value);
+ this->get_internal_single(r_value);
+}
+
+const GVArrayImpl *GVArrayCommon::impl_from_storage() const
+{
+ return storage_.extra_info().get_varray(storage_.get());
+}
+
+IndexRange GVArrayCommon::index_range() const
+{
+ return IndexRange(this->size());
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #GVArray_Slice
+/** \name #GVArray
* \{ */
-GVArray_Slice::GVArray_Slice(const GVArray &varray, const IndexRange slice)
+GVArray::GVArray(const GVArray &other) = default;
+
+GVArray::GVArray(GVArray &&other) noexcept = default;
+
+GVArray::GVArray(const GVArrayImpl *impl) : GVArrayCommon(impl)
{
- if (varray.is_span()) {
- /* Create a new virtual for the sliced span. */
- const GSpan span = varray.get_internal_span();
- const GSpan sliced_span = span.slice(slice.start(), slice.size());
- varray_span_.emplace(sliced_span);
- varray_ = &*varray_span_;
- }
- else if (varray.is_single()) {
- /* Can just use the existing virtual array, because it's the same value for the indices in the
- * slice anyway. */
- varray_ = &varray;
- }
- else {
- /* Generic version when none of the above method works.
- * We don't necessarily want to materialize the input varray because there might be
- * large distances between the required indices. Then we would materialize many elements that
- * are not accessed later on.
- */
- varray_any_.emplace(varray, slice);
- varray_ = &*varray_any_;
+}
+
+GVArray::GVArray(std::shared_ptr<const GVArrayImpl> impl) : GVArrayCommon(std::move(impl))
+{
+}
+
+GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value)
+{
+ return GVArray::For<GVArrayImpl_For_SingleValue>(type, size, value);
+}
+
+GVArray GVArray::ForSingleRef(const CPPType &type, const int64_t size, const void *value)
+{
+ return GVArray::For<GVArrayImpl_For_SingleValueRef_final>(type, size, value);
+}
+
+GVArray GVArray::ForSingleDefault(const CPPType &type, const int64_t size)
+{
+ return GVArray::ForSingleRef(type, size, type.default_value());
+}
+
+GVArray GVArray::ForSpan(GSpan span)
+{
+ return GVArray::For<GVArrayImpl_For_GSpan_final>(span);
+}
+
+class GVArrayImpl_For_GArray : public GVArrayImpl_For_GSpan {
+ protected:
+ GArray<> array_;
+
+ public:
+ GVArrayImpl_For_GArray(GArray<> array)
+ : GVArrayImpl_For_GSpan(array.as_span()), array_(std::move(array))
+ {
}
+};
+
+GVArray GVArray::ForGArray(GArray<> array)
+{
+ return GVArray::For<GVArrayImpl_For_GArray>(array);
+}
+
+GVArray GVArray::ForEmpty(const CPPType &type)
+{
+ return GVArray::ForSpan(GSpan(type));
+}
+
+GVArray GVArray::slice(IndexRange slice) const
+{
+ return GVArray::For<GVArrayImpl_For_SlicedGVArray>(*this, slice);
+}
+
+GVArray &GVArray::operator=(const GVArray &other)
+{
+ this->copy_from(other);
+ return *this;
+}
+
+GVArray &GVArray::operator=(GVArray &&other) noexcept
+{
+ this->move_from(std::move(other));
+ return *this;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVMutableArray
+ * \{ */
+
+GVMutableArray::GVMutableArray(const GVMutableArray &other) = default;
+GVMutableArray::GVMutableArray(GVMutableArray &&other) noexcept = default;
+
+GVMutableArray::GVMutableArray(GVMutableArrayImpl *impl) : GVArrayCommon(impl)
+{
+}
+
+GVMutableArray::GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl)
+ : GVArrayCommon(std::move(impl))
+{
+}
+
+GVMutableArray GVMutableArray::ForSpan(GMutableSpan span)
+{
+ return GVMutableArray::For<GVMutableArrayImpl_For_GMutableSpan_final>(span);
+}
+
+GVMutableArray::operator GVArray() const &
+{
+ GVArray varray;
+ varray.copy_from(*this);
+ return varray;
+}
+
+GVMutableArray::operator GVArray() &&noexcept
+{
+ GVArray varray;
+ varray.move_from(std::move(*this));
+ return varray;
+}
+
+GVMutableArray &GVMutableArray::operator=(const GVMutableArray &other)
+{
+ this->copy_from(other);
+ return *this;
+}
+
+GVMutableArray &GVMutableArray::operator=(GVMutableArray &&other) noexcept
+{
+ this->move_from(std::move(other));
+ return *this;
+}
+
+GVMutableArrayImpl *GVMutableArray::get_implementation() const
+{
+ return this->get_impl();
+}
+
+/* Copy the values from the source buffer to all elements in the virtual array. */
+void GVMutableArray::set_all(const void *src)
+{
+ this->get_impl()->set_all(src);
+}
+
+GMutableSpan GVMutableArray::get_internal_span() const
+{
+ BLI_assert(this->is_span());
+ const GSpan span = impl_->get_internal_span();
+ return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size());
}
/** \} */
diff --git a/source/blender/functions/intern/generic_virtual_vector_array.cc b/source/blender/functions/intern/generic_virtual_vector_array.cc
index 6b90ce993ae..e3c0d3109fa 100644
--- a/source/blender/functions/intern/generic_virtual_vector_array.cc
+++ b/source/blender/functions/intern/generic_virtual_vector_array.cc
@@ -18,13 +18,13 @@
namespace blender::fn {
-void GVArray_For_GVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const
+void GVArray_For_GVVectorArrayIndex::get(const int64_t index_in_vector, void *r_value) const
{
vector_array_.get_vector_element(index_, index_in_vector, r_value);
}
-void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector,
- void *r_value) const
+void GVArray_For_GVVectorArrayIndex::get_to_uninitialized(const int64_t index_in_vector,
+ void *r_value) const
{
type_->default_construct(r_value);
vector_array_.get_vector_element(index_, index_in_vector, r_value);
@@ -32,14 +32,14 @@ void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t ind
int64_t GVVectorArray_For_SingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const
{
- return array_.size();
+ return varray_.size();
}
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);
+ varray_.get(index_in_vector, r_value);
}
bool GVVectorArray_For_SingleGVArray::is_single_vector_impl() const
diff --git a/source/blender/functions/intern/multi_function_parallel.cc b/source/blender/functions/intern/multi_function_parallel.cc
index 5a8c621f0b3..eefe647644d 100644
--- a/source/blender/functions/intern/multi_function_parallel.cc
+++ b/source/blender/functions/intern/multi_function_parallel.cc
@@ -54,7 +54,6 @@ void ParallelMultiFunction::call(IndexMask full_mask, MFParams params, MFContext
const IndexRange input_slice_range{input_slice_start, input_slice_size};
MFParamsBuilder sub_params{fn_, sub_mask.min_array_size()};
- ResourceScope &scope = sub_params.resource_scope();
/* All parameters are sliced so that the wrapped multi-function does not have to take care of
* the index offset. */
@@ -63,8 +62,7 @@ void ParallelMultiFunction::call(IndexMask full_mask, MFParams params, MFContext
switch (param_type.category()) {
case MFParamType::SingleInput: {
const GVArray &varray = params.readonly_single_input(param_index);
- const GVArray &sliced_varray = scope.construct<GVArray_Slice>(varray, input_slice_range);
- sub_params.add_readonly_single_input(sliced_varray);
+ sub_params.add_readonly_single_input(varray.slice(input_slice_range));
break;
}
case MFParamType::SingleMutable: {
diff --git a/source/blender/functions/intern/multi_function_procedure_executor.cc b/source/blender/functions/intern/multi_function_procedure_executor.cc
index 6d2d121bafd..85d0cf4909f 100644
--- a/source/blender/functions/intern/multi_function_procedure_executor.cc
+++ b/source/blender/functions/intern/multi_function_procedure_executor.cc
@@ -66,6 +66,7 @@ struct VariableValue_GVArray : public VariableValue {
VariableValue_GVArray(const GVArray &data) : VariableValue(static_type), data(data)
{
+ BLI_assert(data);
}
};
@@ -756,7 +757,7 @@ class VariableState : NonCopyable, NonMovable {
switch (value_->type) {
case ValueType::GVArray: {
- const GVArray_Typed<bool> varray{this->value_as<VariableValue_GVArray>()->data};
+ const VArray<bool> varray = this->value_as<VariableValue_GVArray>()->data.typed<bool>();
for (const int i : mask) {
r_indices[varray[i]].append(i);
}
diff --git a/source/blender/functions/tests/FN_field_test.cc b/source/blender/functions/tests/FN_field_test.cc
index 041cdbd0f00..16a6c73183d 100644
--- a/source/blender/functions/tests/FN_field_test.cc
+++ b/source/blender/functions/tests/FN_field_test.cc
@@ -34,14 +34,12 @@ class IndexFieldInput final : public FieldInput {
{
}
- const GVArray *get_varray_for_context(const FieldContext &UNUSED(context),
- IndexMask mask,
- ResourceScope &scope) const final
+ GVArray get_varray_for_context(const FieldContext &UNUSED(context),
+ IndexMask mask,
+ ResourceScope &UNUSED(scope)) const final
{
auto index_func = [](int i) { return i; };
- return &scope.construct<
- GVArray_For_EmbeddedVArray<int, VArray_For_Func<int, decltype(index_func)>>>(
- mask.min_array_size(), mask.min_array_size(), index_func);
+ return VArray<int>::ForFunc(mask.min_array_size(), index_func);
}
};
@@ -240,20 +238,20 @@ TEST(field, TwoFunctionsTwoOutputs)
FieldContext field_context;
FieldEvaluator field_evaluator{field_context, &mask};
- const VArray<int> *result_1 = nullptr;
- const VArray<int> *result_2 = nullptr;
+ VArray<int> result_1;
+ VArray<int> result_2;
field_evaluator.add(result_field_1, &result_1);
field_evaluator.add(result_field_2, &result_2);
field_evaluator.evaluate();
- EXPECT_EQ(result_1->get(2), 4);
- EXPECT_EQ(result_1->get(4), 8);
- EXPECT_EQ(result_1->get(6), 12);
- EXPECT_EQ(result_1->get(8), 16);
- EXPECT_EQ(result_2->get(2), 24);
- EXPECT_EQ(result_2->get(4), 28);
- EXPECT_EQ(result_2->get(6), 32);
- EXPECT_EQ(result_2->get(8), 36);
+ EXPECT_EQ(result_1.get(2), 4);
+ EXPECT_EQ(result_1.get(4), 8);
+ EXPECT_EQ(result_1.get(6), 12);
+ EXPECT_EQ(result_1.get(8), 16);
+ EXPECT_EQ(result_2.get(2), 24);
+ EXPECT_EQ(result_2.get(4), 28);
+ EXPECT_EQ(result_2.get(6), 32);
+ EXPECT_EQ(result_2.get(8), 36);
}
TEST(field, SameFieldTwice)
@@ -264,16 +262,16 @@ TEST(field, SameFieldTwice)
FieldContext field_context;
IndexMask mask{IndexRange(2)};
ResourceScope scope;
- Vector<const GVArray *> results = evaluate_fields(
+ Vector<GVArray> results = evaluate_fields(
scope, {constant_field, constant_field}, mask, field_context);
- GVArray_Typed<int> varray1{*results[0]};
- GVArray_Typed<int> varray2{*results[1]};
+ VArray<int> varray1 = results[0].typed<int>();
+ VArray<int> varray2 = results[1].typed<int>();
- EXPECT_EQ(varray1->get(0), 10);
- EXPECT_EQ(varray1->get(1), 10);
- EXPECT_EQ(varray2->get(0), 10);
- EXPECT_EQ(varray2->get(1), 10);
+ EXPECT_EQ(varray1.get(0), 10);
+ EXPECT_EQ(varray1.get(1), 10);
+ EXPECT_EQ(varray2.get(0), 10);
+ EXPECT_EQ(varray2.get(1), 10);
}
TEST(field, IgnoredOutput)
@@ -283,12 +281,12 @@ TEST(field, IgnoredOutput)
FieldContext field_context;
FieldEvaluator field_evaluator{field_context, 10};
- const VArray<int> *results = nullptr;
+ VArray<int> results;
field_evaluator.add(field, &results);
field_evaluator.evaluate();
- EXPECT_EQ(results->get(0), 5);
- EXPECT_EQ(results->get(3), 5);
+ EXPECT_EQ(results.get(0), 5);
+ EXPECT_EQ(results.get(3), 5);
}
} // namespace blender::fn::tests
diff --git a/source/blender/functions/tests/FN_multi_function_procedure_test.cc b/source/blender/functions/tests/FN_multi_function_procedure_test.cc
index 0b4b88fba3d..a0919d7926e 100644
--- a/source/blender/functions/tests/FN_multi_function_procedure_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_procedure_test.cc
@@ -9,6 +9,43 @@
namespace blender::fn::tests {
+TEST(multi_function_procedure, ConstantOutput)
+{
+ /**
+ * procedure(int *var2) {
+ * var1 = 5;
+ * var2 = var1 + var1;
+ * }
+ */
+
+ CustomMF_Constant<int> constant_fn{5};
+ CustomMF_SI_SI_SO<int, int, int> add_fn{"Add", [](int a, int b) { return a + b; }};
+
+ MFProcedure procedure;
+ MFProcedureBuilder builder{procedure};
+
+ auto [var1] = builder.add_call<1>(constant_fn);
+ auto [var2] = builder.add_call<1>(add_fn, {var1, var1});
+ builder.add_destruct(*var1);
+ builder.add_return();
+ builder.add_output_parameter(*var2);
+
+ EXPECT_TRUE(procedure.validate());
+
+ MFProcedureExecutor executor{"My Procedure", procedure};
+
+ MFParamsBuilder params{executor, 2};
+ MFContextBuilder context;
+
+ Array<int> output_array(2);
+ params.add_uninitialized_single_output(output_array.as_mutable_span());
+
+ executor.call(IndexRange(2), params, context);
+
+ EXPECT_EQ(output_array[0], 10);
+ EXPECT_EQ(output_array[1], 10);
+}
+
TEST(multi_function_procedure, SimpleTest)
{
/**