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:
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh2
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh211
-rw-r--r--source/blender/blenlib/BLI_virtual_vector_array.hh95
-rw-r--r--source/blender/blenlib/CMakeLists.txt3
-rw-r--r--source/blender/blenlib/tests/BLI_virtual_array_test.cc31
-rw-r--r--source/blender/functions/CMakeLists.txt11
-rw-r--r--source/blender/functions/FN_array_spans.hh206
-rw-r--r--source/blender/functions/FN_generic_span.hh158
-rw-r--r--source/blender/functions/FN_generic_vector_array.hh195
-rw-r--r--source/blender/functions/FN_generic_virtual_array.hh275
-rw-r--r--source/blender/functions/FN_generic_virtual_vector_array.hh188
-rw-r--r--source/blender/functions/FN_multi_function_builder.hh63
-rw-r--r--source/blender/functions/FN_multi_function_params.hh65
-rw-r--r--source/blender/functions/FN_multi_function_signature.hh8
-rw-r--r--source/blender/functions/FN_spans.hh462
-rw-r--r--source/blender/functions/intern/generic_vector_array.cc104
-rw-r--r--source/blender/functions/intern/generic_virtual_array.cc107
-rw-r--r--source/blender/functions/intern/generic_virtual_vector_array.cc67
-rw-r--r--source/blender/functions/intern/multi_function_network_evaluation.cc191
-rw-r--r--source/blender/functions/tests/FN_array_spans_test.cc134
-rw-r--r--source/blender/functions/tests/FN_generic_span_test.cc53
-rw-r--r--source/blender/functions/tests/FN_generic_vector_array_test.cc108
-rw-r--r--source/blender/functions/tests/FN_multi_function_network_test.cc33
-rw-r--r--source/blender/functions/tests/FN_multi_function_test.cc57
-rw-r--r--source/blender/functions/tests/FN_spans_test.cc222
-rw-r--r--source/blender/nodes/function/nodes/node_fn_object_transforms.cc2
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_float.cc6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_valToRgb.cc2
31 files changed, 1655 insertions, 1422 deletions
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index 653c0f0d85d..120b4e08b9c 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -19,7 +19,7 @@
#include <mutex>
#include "FN_cpp_type.hh"
-#include "FN_spans.hh"
+#include "FN_generic_span.hh"
#include "BKE_attribute.h"
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
new file mode 100644
index 00000000000..51d2e820504
--- /dev/null
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -0,0 +1,211 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ *
+ * A virtual array is a data structure that behaves similar to an array, but its elements are
+ * accessed through virtual methods. This improves the decoupling of a function from its callers,
+ * because it does not have to know exactly how the data is layed out in memory, or if it is stored
+ * in memory at all. It could just as well be computed on the fly.
+ *
+ * Taking a virtual array as parameter instead of a more specific non-virtual type has some
+ * tradeoffs. Access to individual elements of the individual elements is higher due to function
+ * call overhead. On the other hand, potential callers don't have to convert the data into the
+ * specific format required for the function. This can be a costly conversion if only few of the
+ * elements are accessed in the end.
+ *
+ * Functions taking a virtual array as input can still optimize for different data layouts. For
+ * example, they can check if the array is stored as an array internally or if it is the same
+ * element for all indices. Whether it is worth to optimize for different data layouts in a
+ * function has to be decided on a case by case basis. One should always do some benchmarking to
+ * see of the increased compile time and binary size is worth it.
+ */
+
+#include "BLI_span.hh"
+
+namespace blender {
+
+/* An immutable virtual array. */
+template<typename T> class VArray {
+ protected:
+ int64_t size_;
+
+ public:
+ VArray(const int64_t size) : size_(size)
+ {
+ BLI_assert(size_ >= 0);
+ }
+
+ virtual ~VArray() = default;
+
+ T get(const int64_t index) const
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ return this->get_impl(index);
+ }
+
+ int64_t size() const
+ {
+ return size_;
+ }
+
+ bool is_empty() const
+ {
+ return size_ == 0;
+ }
+
+ /* 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();
+ }
+
+ /* Returns the internally used span of the virtual array. This invokes undefined behavior is the
+ * virtual array is not stored as a span internally. */
+ Span<T> get_span() const
+ {
+ BLI_assert(this->is_span());
+ if (size_ == 0) {
+ return {};
+ }
+ return this->get_span_impl();
+ }
+
+ /* 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();
+ }
+
+ /* Returns the value that is returned for every index. This invokes undefined behavior if the
+ * virtual array would not return the same value for every index. */
+ T get_single() const
+ {
+ BLI_assert(this->is_single());
+ if (size_ == 1) {
+ return this->get(0);
+ }
+ return this->get_single_impl();
+ }
+
+ T operator[](const int64_t index) const
+ {
+ return this->get(index);
+ }
+
+ protected:
+ virtual T get_impl(const int64_t index) const = 0;
+
+ virtual bool is_span_impl() const
+ {
+ return false;
+ }
+
+ virtual Span<T> get_span_impl() const
+ {
+ BLI_assert(false);
+ return {};
+ }
+
+ virtual bool is_single_impl() const
+ {
+ return false;
+ }
+
+ virtual T get_single_impl() const
+ {
+ /* Provide a default implementation, so that subclasses don't have to provide it. This method
+ * should never be called because `is_single_impl` returns false by default. */
+ BLI_assert(false);
+ return T();
+ }
+};
+
+/* A virtual array implementation for a span. */
+template<typename T> class VArrayForSpan : public VArray<T> {
+ private:
+ const T *data_;
+
+ public:
+ VArrayForSpan(const Span<T> data) : VArray<T>(data.size()), data_(data.data())
+ {
+ }
+
+ protected:
+ T get_impl(const int64_t index) const override
+ {
+ return data_[index];
+ }
+
+ bool is_span_impl() const override
+ {
+ return true;
+ }
+
+ Span<T> get_span_impl() const override
+ {
+ return Span<T>(data_, this->size_);
+ }
+};
+
+/* A virtual array implementation that returns the same value for every index. */
+template<typename T> class VArrayForSingle : public VArray<T> {
+ private:
+ T value_;
+
+ public:
+ VArrayForSingle(T value, const int64_t size) : VArray<T>(size), value_(std::move(value))
+ {
+ }
+
+ protected:
+ T get_impl(const int64_t UNUSED(index)) const override
+ {
+ return value_;
+ }
+
+ bool is_span_impl() const override
+ {
+ return this->size_ == 1;
+ }
+
+ Span<T> get_span_impl() const override
+ {
+ return Span<T>(&value_, 1);
+ }
+
+ bool is_single_impl() const override
+ {
+ return true;
+ }
+
+ T get_single_impl() const override
+ {
+ return value_;
+ }
+};
+
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_virtual_vector_array.hh b/source/blender/blenlib/BLI_virtual_vector_array.hh
new file mode 100644
index 00000000000..ab5afd2d80a
--- /dev/null
+++ b/source/blender/blenlib/BLI_virtual_vector_array.hh
@@ -0,0 +1,95 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ *
+ * A virtual vector array gives access to an array of vectors. The individual vectors in the array
+ * can have different sizes.
+ *
+ * The tradeoffs here are similar to virtual arrays.
+ */
+
+#include "BLI_virtual_array.hh"
+
+namespace blender {
+
+/* A readonly virtual array of vectors. */
+template<typename T> class VVectorArray {
+ protected:
+ int64_t size_;
+
+ public:
+ VVectorArray(const int64_t size) : size_(size)
+ {
+ BLI_assert(size >= 0);
+ }
+
+ virtual ~VVectorArray() = default;
+
+ /* Returns the number of vectors in the vector array. */
+ int64_t size() const
+ {
+ return size_;
+ }
+
+ /* Returns true when there is no vector in the vector array. */
+ bool is_empty() const
+ {
+ return size_ == 0;
+ }
+
+ /* Returns the size of the vector at the given index. */
+ int64_t get_vector_size(const int64_t index) const
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ return this->get_vector_size_impl(index);
+ }
+
+ /* Returns an element from one of the vectors. */
+ T get_vector_element(const int64_t index, const int64_t index_in_vector) const
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ BLI_assert(index_in_vector >= 0);
+ BLI_assert(index_in_vector < this->get_vector_size(index));
+ return this->get_vector_element_impl(index, index_in_vector);
+ }
+
+ /* Returns true when the same vector is used at every index. */
+ bool is_single_vector() const
+ {
+ if (size_ == 1) {
+ return true;
+ }
+ return this->is_single_vector_impl();
+ }
+
+ protected:
+ virtual int64_t get_vector_size_impl(const int64_t index) const = 0;
+
+ virtual T get_vector_element_impl(const int64_t index, const int64_t index_in_vetor) const = 0;
+
+ virtual bool is_single_vector_impl() const
+ {
+ return false;
+ }
+};
+
+} // namespace blender
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 5a851b7b2cb..37b0f742b8b 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -296,6 +296,8 @@ set(SRC
BLI_vector_set.hh
BLI_vector_set_slots.hh
BLI_vfontdata.h
+ BLI_virtual_array.hh
+ BLI_virtual_vector_array.hh
BLI_voronoi_2d.h
BLI_voxel.h
BLI_winstuff.h
@@ -432,6 +434,7 @@ if(WITH_GTESTS)
tests/BLI_task_test.cc
tests/BLI_vector_set_test.cc
tests/BLI_vector_test.cc
+ tests/BLI_virtual_array_test.cc
tests/BLI_exception_safety_test_utils.hh
)
diff --git a/source/blender/blenlib/tests/BLI_virtual_array_test.cc b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
new file mode 100644
index 00000000000..ac25229cd69
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
@@ -0,0 +1,31 @@
+/* Apache License, Version 2.0 */
+
+#include "BLI_strict_flags.h"
+#include "BLI_virtual_array.hh"
+#include "testing/testing.h"
+
+namespace blender::tests {
+
+TEST(virtual_array, ForSpan)
+{
+ std::array<int, 5> data = {3, 4, 5, 6, 7};
+ VArrayForSpan<int> varray{data};
+ EXPECT_EQ(varray.size(), 5);
+ EXPECT_EQ(varray.get(0), 3);
+ EXPECT_EQ(varray.get(4), 7);
+ EXPECT_TRUE(varray.is_span());
+ EXPECT_FALSE(varray.is_single());
+ EXPECT_EQ(varray.get_span().data(), data.data());
+}
+
+TEST(virtual_array, ForSingle)
+{
+ VArrayForSingle<int> varray{10, 4};
+ EXPECT_EQ(varray.size(), 4);
+ EXPECT_EQ(varray.get(0), 10);
+ EXPECT_EQ(varray.get(3), 10);
+ EXPECT_FALSE(varray.is_span());
+ EXPECT_TRUE(varray.is_single());
+}
+
+} // namespace blender::tests
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index 608d7287bb2..809294ad274 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -28,18 +28,23 @@ set(INC_SYS
set(SRC
intern/cpp_types.cc
+ intern/generic_vector_array.cc
+ intern/generic_virtual_array.cc
+ intern/generic_virtual_vector_array.cc
intern/multi_function.cc
intern/multi_function_builder.cc
intern/multi_function_network.cc
intern/multi_function_network_evaluation.cc
intern/multi_function_network_optimization.cc
- FN_array_spans.hh
FN_cpp_type.hh
FN_cpp_type_make.hh
FN_generic_pointer.hh
+ FN_generic_span.hh
FN_generic_value_map.hh
FN_generic_vector_array.hh
+ FN_generic_virtual_array.hh
+ FN_generic_virtual_vector_array.hh
FN_multi_function.hh
FN_multi_function_builder.hh
FN_multi_function_context.hh
@@ -50,7 +55,6 @@ set(SRC
FN_multi_function_param_type.hh
FN_multi_function_params.hh
FN_multi_function_signature.hh
- FN_spans.hh
)
set(LIB
@@ -61,12 +65,11 @@ blender_add_lib(bf_functions "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
if(WITH_GTESTS)
set(TEST_SRC
- tests/FN_array_spans_test.cc
tests/FN_cpp_type_test.cc
+ tests/FN_generic_span_test.cc
tests/FN_generic_vector_array_test.cc
tests/FN_multi_function_network_test.cc
tests/FN_multi_function_test.cc
- tests/FN_spans_test.cc
)
set(TEST_LIB
bf_functions
diff --git a/source/blender/functions/FN_array_spans.hh b/source/blender/functions/FN_array_spans.hh
deleted file mode 100644
index afcff944957..00000000000
--- a/source/blender/functions/FN_array_spans.hh
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-/** \file
- * \ingroup fn
- *
- * An ArraySpan is a span where every element contains an array (instead of a single element as is
- * the case in a normal span). Its main use case is to reference many small arrays.
- */
-
-#include "FN_spans.hh"
-
-namespace blender::fn {
-
-/**
- * Depending on the use case, the referenced data might have a different structure. More
- * categories can be added when necessary.
- */
-enum class VArraySpanCategory {
- SingleArray,
- StartsAndSizes,
-};
-
-template<typename T> class VArraySpanBase {
- protected:
- int64_t virtual_size_;
- VArraySpanCategory category_;
-
- union {
- struct {
- const T *start;
- int64_t size;
- } single_array;
- struct {
- const T *const *starts;
- const int64_t *sizes;
- } starts_and_sizes;
- } data_;
-
- public:
- bool is_single_array() const
- {
- switch (category_) {
- case VArraySpanCategory::SingleArray:
- return true;
- case VArraySpanCategory::StartsAndSizes:
- return virtual_size_ == 1;
- }
- BLI_assert(false);
- return false;
- }
-
- bool is_empty() const
- {
- return this->virtual_size_ == 0;
- }
-
- int64_t size() const
- {
- return this->virtual_size_;
- }
-};
-
-/**
- * A virtual array span. Every element of this span contains a virtual span. So it behaves like
- * a blender::Span, but might not be backed up by an actual array.
- */
-template<typename T> class VArraySpan : public VArraySpanBase<T> {
- private:
- friend class GVArraySpan;
-
- VArraySpan(const VArraySpanBase<void> &other)
- {
- memcpy(this, &other, sizeof(VArraySpanBase<void>));
- }
-
- public:
- VArraySpan()
- {
- this->virtual_size_ = 0;
- this->category_ = VArraySpanCategory::StartsAndSizes;
- this->data_.starts_and_sizes.starts = nullptr;
- this->data_.starts_and_sizes.sizes = nullptr;
- }
-
- VArraySpan(Span<T> span, int64_t virtual_size)
- {
- BLI_assert(virtual_size >= 0);
- this->virtual_size_ = virtual_size;
- this->category_ = VArraySpanCategory::SingleArray;
- this->data_.single_array.start = span.data();
- this->data_.single_array.size = span.size();
- }
-
- VArraySpan(Span<const T *> starts, Span<int64_t> sizes)
- {
- BLI_assert(starts.size() == sizes.size());
- this->virtual_size_ = starts.size();
- this->category_ = VArraySpanCategory::StartsAndSizes;
- this->data_.starts_and_sizes.starts = starts.begin();
- this->data_.starts_and_sizes.sizes = sizes.begin();
- }
-
- VSpan<T> operator[](int64_t index) const
- {
- BLI_assert(index >= 0);
- BLI_assert(index < this->virtual_size_);
- switch (this->category_) {
- case VArraySpanCategory::SingleArray:
- return VSpan<T>(Span<T>(this->data_.single_array.start, this->data_.single_array.size));
- case VArraySpanCategory::StartsAndSizes:
- return VSpan<T>(Span<T>(this->data_.starts_and_sizes.starts[index],
- this->data_.starts_and_sizes.sizes[index]));
- }
- BLI_assert(false);
- return {};
- }
-};
-
-/**
- * A generic virtual array span. It's just like a VArraySpan, but the type is only known at
- * run-time.
- */
-class GVArraySpan : public VArraySpanBase<void> {
- private:
- const CPPType *type_;
-
- GVArraySpan() = default;
-
- public:
- GVArraySpan(const CPPType &type)
- {
- this->type_ = &type;
- this->virtual_size_ = 0;
- this->category_ = VArraySpanCategory::StartsAndSizes;
- this->data_.starts_and_sizes.starts = nullptr;
- this->data_.starts_and_sizes.sizes = nullptr;
- }
-
- GVArraySpan(GSpan array, int64_t virtual_size)
- {
- this->type_ = &array.type();
- this->virtual_size_ = virtual_size;
- this->category_ = VArraySpanCategory::SingleArray;
- this->data_.single_array.start = array.data();
- this->data_.single_array.size = array.size();
- }
-
- GVArraySpan(const CPPType &type, Span<const void *> starts, Span<int64_t> sizes)
- {
- BLI_assert(starts.size() == sizes.size());
- this->type_ = &type;
- this->virtual_size_ = starts.size();
- this->category_ = VArraySpanCategory::StartsAndSizes;
- this->data_.starts_and_sizes.starts = (void **)starts.begin();
- this->data_.starts_and_sizes.sizes = sizes.begin();
- }
-
- template<typename T> GVArraySpan(VArraySpan<T> other)
- {
- this->type_ = &CPPType::get<T>();
- memcpy(this, &other, sizeof(VArraySpanBase<void>));
- }
-
- const CPPType &type() const
- {
- return *this->type_;
- }
-
- template<typename T> VArraySpan<T> typed() const
- {
- BLI_assert(type_->is<T>());
- return VArraySpan<T>(*this);
- }
-
- GVSpan operator[](int64_t index) const
- {
- BLI_assert(index < virtual_size_);
- switch (category_) {
- case VArraySpanCategory::SingleArray:
- return GVSpan(GSpan(*type_, data_.single_array.start, data_.single_array.size));
- case VArraySpanCategory::StartsAndSizes:
- return GVSpan(GSpan(
- *type_, data_.starts_and_sizes.starts[index], data_.starts_and_sizes.sizes[index]));
- }
- BLI_assert(false);
- return GVSpan(*type_);
- }
-};
-
-} // namespace blender::fn
diff --git a/source/blender/functions/FN_generic_span.hh b/source/blender/functions/FN_generic_span.hh
new file mode 100644
index 00000000000..31b67dd3d70
--- /dev/null
+++ b/source/blender/functions/FN_generic_span.hh
@@ -0,0 +1,158 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup fn
+ */
+
+#include "BLI_span.hh"
+
+#include "FN_cpp_type.hh"
+
+namespace blender::fn {
+
+/**
+ * A generic span. It behaves just like a blender::Span<T>, but the type is only known at run-time.
+ */
+class GSpan {
+ private:
+ const CPPType *type_;
+ const void *data_;
+ int64_t size_;
+
+ public:
+ GSpan(const CPPType &type, const void *buffer, int64_t size)
+ : type_(&type), data_(buffer), size_(size)
+ {
+ BLI_assert(size >= 0);
+ BLI_assert(buffer != nullptr || size == 0);
+ BLI_assert(type.pointer_has_valid_alignment(buffer));
+ }
+
+ GSpan(const CPPType &type) : GSpan(type, nullptr, 0)
+ {
+ }
+
+ template<typename T>
+ GSpan(Span<T> array)
+ : GSpan(CPPType::get<T>(), static_cast<const void *>(array.data()), array.size())
+ {
+ }
+
+ const CPPType &type() const
+ {
+ return *type_;
+ }
+
+ bool is_empty() const
+ {
+ return size_ == 0;
+ }
+
+ int64_t size() const
+ {
+ return size_;
+ }
+
+ const void *data() const
+ {
+ return data_;
+ }
+
+ const void *operator[](int64_t index) const
+ {
+ BLI_assert(index < size_);
+ return POINTER_OFFSET(data_, type_->size() * index);
+ }
+
+ template<typename T> Span<T> typed() const
+ {
+ BLI_assert(type_->is<T>());
+ return Span<T>(static_cast<const T *>(data_), size_);
+ }
+};
+
+/**
+ * A generic mutable span. It behaves just like a blender::MutableSpan<T>, but the type is only
+ * known at run-time.
+ */
+class GMutableSpan {
+ private:
+ const CPPType *type_;
+ void *data_;
+ int64_t size_;
+
+ public:
+ GMutableSpan(const CPPType &type, void *buffer, int64_t size)
+ : type_(&type), data_(buffer), size_(size)
+ {
+ BLI_assert(size >= 0);
+ BLI_assert(buffer != nullptr || size == 0);
+ BLI_assert(type.pointer_has_valid_alignment(buffer));
+ }
+
+ GMutableSpan(const CPPType &type) : GMutableSpan(type, nullptr, 0)
+ {
+ }
+
+ template<typename T>
+ GMutableSpan(MutableSpan<T> array)
+ : GMutableSpan(CPPType::get<T>(), static_cast<void *>(array.begin()), array.size())
+ {
+ }
+
+ operator GSpan() const
+ {
+ return GSpan(*type_, data_, size_);
+ }
+
+ const CPPType &type() const
+ {
+ return *type_;
+ }
+
+ bool is_empty() const
+ {
+ return size_ == 0;
+ }
+
+ int64_t size() const
+ {
+ return size_;
+ }
+
+ void *data() const
+ {
+ return data_;
+ }
+
+ void *operator[](int64_t index) const
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ return POINTER_OFFSET(data_, type_->size() * index);
+ }
+
+ template<typename T> MutableSpan<T> typed() const
+ {
+ BLI_assert(type_->is<T>());
+ return MutableSpan<T>(static_cast<T *>(data_), size_);
+ }
+};
+
+} // namespace blender::fn
diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/functions/FN_generic_vector_array.hh
index dc5ad3c36ab..ae6eb8a614f 100644
--- a/source/blender/functions/FN_generic_vector_array.hh
+++ b/source/blender/functions/FN_generic_vector_array.hh
@@ -19,75 +19,52 @@
/** \file
* \ingroup fn
*
- * A `GVectorArray` is a container for a fixed amount of dynamically growing arrays with a generic
- * type. Its main use case is to store many small vectors with few separate allocations. Using this
- * structure is generally more efficient than allocating each small vector separately.
- *
- * `GVectorArrayRef<T>` is a typed reference to a GVectorArray and makes it easier and safer to
- * work with the class when the type is known at compile time.
+ * A`GVectorArray` is a container for a fixed amount of dynamically growing vectors with a generic
+ * data type. Its main use case is to store many small vectors with few separate allocations. Using
+ * this structure is generally more efficient than allocating each vector separately.
*/
-#include "FN_array_spans.hh"
-#include "FN_cpp_type.hh"
-
#include "BLI_array.hh"
#include "BLI_linear_allocator.hh"
-#include "BLI_utility_mixins.hh"
-namespace blender::fn {
+#include "FN_generic_virtual_vector_array.hh"
-template<typename T> class GVectorArrayRef;
+namespace blender::fn {
+/* An array of vectors containing elements of a generic type. */
class GVectorArray : NonCopyable, NonMovable {
private:
- const CPPType &type_;
- int64_t element_size_;
- Array<void *, 1> starts_;
- Array<int64_t, 1> lengths_;
- Array<int64_t, 1> capacities_;
+ struct Item {
+ void *start = nullptr;
+ int64_t length = 0;
+ int64_t capacity = 0;
+ };
+
+ /* Use a linear allocator to pack many small vectors together. Currently, memory from reallocated
+ * vectors is not reused. This can be improved in the future. */
LinearAllocator<> allocator_;
-
- template<typename T> friend class GVectorArrayRef;
+ /* The data type of individual elements. */
+ const CPPType &type_;
+ /* The size of an individual element. This is inlined from `type_.size()` for easier access. */
+ const int64_t element_size_;
+ /* The individual vectors. */
+ Array<Item> items_;
public:
GVectorArray() = delete;
- GVectorArray(const CPPType &type, int64_t array_size)
- : type_(type),
- element_size_(type.size()),
- starts_(array_size),
- lengths_(array_size),
- capacities_(array_size)
- {
- starts_.as_mutable_span().fill(nullptr);
- lengths_.as_mutable_span().fill(0);
- capacities_.as_mutable_span().fill(0);
- }
-
- ~GVectorArray()
- {
- if (type_.is_trivially_destructible()) {
- return;
- }
+ GVectorArray(const CPPType &type, int64_t array_size);
- for (int64_t i : starts_.index_range()) {
- type_.destruct_n(starts_[i], lengths_[i]);
- }
- }
+ ~GVectorArray();
- operator GVArraySpan() const
+ int64_t size() const
{
- return GVArraySpan(type_, starts_, lengths_);
+ return items_.size();
}
bool is_empty() const
{
- return starts_.size() == 0;
- }
-
- int64_t size() const
- {
- return starts_.size();
+ return items_.is_empty();
}
const CPPType &type() const
@@ -95,109 +72,89 @@ class GVectorArray : NonCopyable, NonMovable {
return type_;
}
- Span<const void *> starts() const
- {
- return starts_;
- }
-
- Span<int64_t> lengths() const
- {
- return lengths_;
- }
-
- void append(int64_t index, const void *src)
- {
- int64_t old_length = lengths_[index];
- if (old_length == capacities_[index]) {
- this->grow_at_least_one(index);
- }
-
- void *dst = POINTER_OFFSET(starts_[index], element_size_ * old_length);
- type_.copy_to_uninitialized(src, dst);
- lengths_[index]++;
- }
+ void append(int64_t index, const void *value);
- void extend(int64_t index, GVSpan span)
- {
- BLI_assert(type_ == span.type());
- for (int64_t i = 0; i < span.size(); i++) {
- this->append(index, span[i]);
- }
- }
+ /* Add multiple elements to a single vector. */
+ void extend(int64_t index, const GVArray &values);
+ void extend(int64_t index, GSpan values);
- void extend(IndexMask mask, GVArraySpan array_span)
- {
- BLI_assert(type_ == array_span.type());
- BLI_assert(mask.min_array_size() <= array_span.size());
- for (int64_t i : mask) {
- this->extend(i, array_span[i]);
- }
- }
+ /* Add multiple elements to multiple vectors. */
+ void extend(IndexMask mask, const GVVectorArray &values);
+ void extend(IndexMask mask, const GVectorArray &values);
- GMutableSpan operator[](int64_t index)
- {
- BLI_assert(index < starts_.size());
- return GMutableSpan(type_, starts_[index], lengths_[index]);
- }
- template<typename T> GVectorArrayRef<T> typed()
- {
- return GVectorArrayRef<T>(*this);
- }
+ GMutableSpan operator[](int64_t index);
+ GSpan operator[](int64_t index) const;
private:
- void grow_at_least_one(int64_t index)
- {
- BLI_assert(lengths_[index] == capacities_[index]);
- int64_t new_capacity = lengths_[index] * 2 + 1;
-
- void *new_buffer = allocator_.allocate(element_size_ * new_capacity, type_.alignment());
- type_.relocate_to_uninitialized_n(starts_[index], new_buffer, lengths_[index]);
-
- starts_[index] = new_buffer;
- capacities_[index] = new_capacity;
- }
+ void realloc_to_at_least(Item &item, int64_t min_capacity);
};
-template<typename T> class GVectorArrayRef {
+/* A non-owning typed mutable reference to an `GVectorArray`. It simplifies access when the type of
+ * the data is known at compile time. */
+template<typename T> class GVectorArray_TypedMutableRef {
private:
GVectorArray *vector_array_;
public:
- GVectorArrayRef(GVectorArray &vector_array) : vector_array_(&vector_array)
+ GVectorArray_TypedMutableRef(GVectorArray &vector_array) : vector_array_(&vector_array)
{
- BLI_assert(vector_array.type_.is<T>());
+ BLI_assert(vector_array_->type().is<T>());
}
- void append(int64_t index, const T &value)
+ int64_t size() const
+ {
+ return vector_array_->size();
+ }
+
+ bool is_empty() const
+ {
+ return vector_array_->is_empty();
+ }
+
+ void append(const int64_t index, const T &value)
{
vector_array_->append(index, &value);
}
- void extend(int64_t index, Span<T> values)
+ void extend(const int64_t index, const Span<T> values)
{
vector_array_->extend(index, values);
}
- void extend(int64_t index, VSpan<T> values)
+ void extend(const int64_t index, const VArray<T> &values)
{
- vector_array_->extend(index, GVSpan(values));
+ GVArrayForVArray<T> array{values};
+ this->extend(index, array);
}
- MutableSpan<T> operator[](int64_t index)
+ MutableSpan<T> operator[](const int64_t index)
{
- BLI_assert(index < vector_array_->starts_.size());
- return MutableSpan<T>(static_cast<T *>(vector_array_->starts_[index]),
- vector_array_->lengths_[index]);
+ return (*vector_array_)[index].typed<T>();
}
+};
- int64_t size() const
+/* A generic virtual vector array implementation for a `GVectorArray`. */
+class GVVectorArrayForGVectorArray : public GVVectorArray {
+ private:
+ const GVectorArray &vector_array_;
+
+ public:
+ GVVectorArrayForGVectorArray(const GVectorArray &vector_array)
+ : GVVectorArray(vector_array.type(), vector_array.size()), vector_array_(vector_array)
{
- return vector_array_->size();
}
- bool is_empty() const
+ protected:
+ int64_t get_vector_size_impl(const int64_t index) const override
{
- return vector_array_->is_empty();
+ return vector_array_[index].size();
+ }
+
+ void get_vector_element_impl(const int64_t index,
+ const int64_t index_in_vector,
+ void *r_value) const override
+ {
+ type_->copy_to_initialized(vector_array_[index][index_in_vector], r_value);
}
};
diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh
new file mode 100644
index 00000000000..c60476c4631
--- /dev/null
+++ b/source/blender/functions/FN_generic_virtual_array.hh
@@ -0,0 +1,275 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup fn
+ *
+ * A generic virtual array is the same as a virtual array from blenlib, except for the fact that
+ * the data type is only known at runtime.
+ */
+
+#include "BLI_virtual_array.hh"
+
+#include "FN_generic_span.hh"
+
+namespace blender::fn {
+
+/* A generically typed version of `VArray<T>`. */
+class GVArray {
+ protected:
+ const CPPType *type_;
+ int64_t size_;
+
+ public:
+ GVArray(const CPPType &type, const int64_t size) : type_(&type), size_(size)
+ {
+ BLI_assert(size_ >= 0);
+ }
+
+ virtual ~GVArray() = default;
+
+ const CPPType &type() const
+ {
+ return *type_;
+ }
+
+ int64_t size() const
+ {
+ return size_;
+ }
+
+ bool is_empty() const
+ {
+ return size_;
+ }
+
+ /* 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);
+ }
+
+ /* 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);
+ }
+
+ /* 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();
+ }
+
+ /* Returns the internally used span of the virtual array. This invokes undefined behavior is the
+ * virtual array is not stored as a span internally. */
+ GSpan get_span() const
+ {
+ BLI_assert(this->is_span());
+ if (size_ == 0) {
+ return GSpan(*type_);
+ }
+ return this->get_span_impl();
+ }
+
+ /* 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();
+ }
+
+ /* Copies the value that is used for every element into `r_value`, which is expected to point to
+ * initialized memory. This invokes undefined behavior if the virtual array would not return the
+ * same value for every index. */
+ void get_single(void *r_value) const
+ {
+ BLI_assert(this->is_single());
+ if (size_ == 1) {
+ this->get(0, r_value);
+ }
+ this->get_single_impl(r_value);
+ }
+
+ /* Same as `get_single`, but `r_value` points to initialized memory. */
+ void get_single_to_uninitialized(void *r_value) const
+ {
+ type_->construct_default(r_value);
+ this->get_single(r_value);
+ }
+
+ void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
+
+ protected:
+ virtual void get_impl(const int64_t index, void *r_value) const;
+ virtual void get_to_uninitialized_impl(const int64_t index, void *r_value) const = 0;
+
+ virtual bool is_span_impl() const;
+ virtual GSpan get_span_impl() const;
+
+ virtual bool is_single_impl() const;
+ virtual void get_single_impl(void *UNUSED(r_value)) const;
+};
+
+class GVArrayForGSpan : public GVArray {
+ protected:
+ const void *data_;
+ const int64_t element_size_;
+
+ public:
+ GVArrayForGSpan(const GSpan span)
+ : GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size())
+ {
+ }
+
+ protected:
+ void get_impl(const int64_t index, void *r_value) const override;
+ void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
+
+ bool is_span_impl() const override;
+ GSpan get_span_impl() const override;
+};
+
+class GVArrayForEmpty : public GVArray {
+ public:
+ GVArrayForEmpty(const CPPType &type) : GVArray(type, 0)
+ {
+ }
+
+ protected:
+ void get_to_uninitialized_impl(const int64_t UNUSED(index), void *UNUSED(r_value)) const override
+ {
+ BLI_assert(false);
+ }
+};
+
+class GVArrayForSingleValueRef : public GVArray {
+ private:
+ const void *value_;
+
+ public:
+ GVArrayForSingleValueRef(const CPPType &type, const int64_t size, const void *value)
+ : GVArray(type, size), value_(value)
+ {
+ }
+
+ protected:
+ void get_impl(const int64_t index, void *r_value) const override;
+ void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
+
+ bool is_span_impl() const override;
+ GSpan get_span_impl() const override;
+
+ bool is_single_impl() const override;
+ void get_single_impl(void *r_value) const override;
+};
+
+template<typename T> class GVArrayForVArray : public GVArray {
+ private:
+ const VArray<T> &array_;
+
+ public:
+ GVArrayForVArray(const VArray<T> &array)
+ : GVArray(CPPType::get<T>(), array.size()), array_(array)
+ {
+ }
+
+ protected:
+ void get_impl(const int64_t index, void *r_value) const override
+ {
+ *(T *)r_value = array_.get(index);
+ }
+
+ void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ {
+ new (r_value) T(array_.get(index));
+ }
+
+ bool is_span_impl() const override
+ {
+ return array_.is_span();
+ }
+
+ GSpan get_span_impl() const override
+ {
+ return GSpan(array_.get_span());
+ }
+
+ bool is_single_impl() const override
+ {
+ return array_.is_single();
+ }
+
+ void get_single_impl(void *r_value) const override
+ {
+ *(T *)r_value = array_.get_single();
+ }
+};
+
+template<typename T> class VArrayForGVArray : public VArray<T> {
+ private:
+ const GVArray &array_;
+
+ public:
+ VArrayForGVArray(const GVArray &array) : VArray<T>(array.size()), array_(array)
+ {
+ BLI_assert(array_.type().is<T>());
+ }
+
+ protected:
+ T get_impl(const int64_t index) const override
+ {
+ T value;
+ array_.get(index, &value);
+ return value;
+ }
+
+ bool is_span_impl() const override
+ {
+ return array_.is_span();
+ }
+
+ Span<T> get_span_impl() const override
+ {
+ return array_.get_span().typed<T>();
+ }
+
+ bool is_single_impl() const override
+ {
+ return array_.is_single();
+ }
+
+ T get_single_impl() const override
+ {
+ T value;
+ array_.get_single(&value);
+ return value;
+ }
+};
+
+} // 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
new file mode 100644
index 00000000000..22d1e5641e5
--- /dev/null
+++ b/source/blender/functions/FN_generic_virtual_vector_array.hh
@@ -0,0 +1,188 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup fn
+ *
+ * A generic virtual vector array is essentially the same as a virtual vector array from blenlib,
+ * but its data type is only known at runtime.
+ */
+
+#include "FN_generic_virtual_array.hh"
+
+#include "BLI_virtual_vector_array.hh"
+
+namespace blender::fn {
+
+/* A generically typed version of `VVectorArray`. */
+class GVVectorArray {
+ protected:
+ const CPPType *type_;
+ int64_t size_;
+
+ public:
+ GVVectorArray(const CPPType &type, const int64_t size) : type_(&type), size_(size)
+ {
+ }
+
+ virtual ~GVVectorArray() = default;
+
+ /* Returns the number of vectors in the vector array. */
+ int64_t size() const
+ {
+ return size_;
+ }
+
+ /* Returns true when there is no vector in the vector array. */
+ bool is_empty() const
+ {
+ return size_ == 0;
+ }
+
+ const CPPType &type() const
+ {
+ return *type_;
+ }
+
+ /* Returns the size of the vector at the given index. */
+ int64_t get_vector_size(const int64_t index) const
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ return this->get_vector_size_impl(index);
+ }
+
+ /* Copies an element from one of the vectors into `r_value`, which is expected to point to
+ * initialized memory. */
+ void get_vector_element(const int64_t index, const int64_t index_in_vector, void *r_value) const
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ BLI_assert(index_in_vector >= 0);
+ BLI_assert(index_in_vector < this->get_vector_size(index));
+ this->get_vector_element_impl(index, index_in_vector, r_value);
+ }
+
+ /* Returns true when the same vector is used at every index. */
+ bool is_single_vector() const
+ {
+ if (size_ == 1) {
+ return true;
+ }
+ return this->is_single_vector_impl();
+ }
+
+ protected:
+ virtual int64_t get_vector_size_impl(const int64_t index) const = 0;
+
+ virtual void get_vector_element_impl(const int64_t index,
+ const int64_t index_in_vector,
+ void *r_value) const = 0;
+
+ virtual bool is_single_vector_impl() const
+ {
+ return false;
+ }
+};
+
+class GVArrayForGVVectorArrayIndex : public GVArray {
+ private:
+ const GVVectorArray &vector_array_;
+ const int64_t index_;
+
+ public:
+ GVArrayForGVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index)
+ : GVArray(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;
+};
+
+class GVVectorArrayForSingleGVArray : public GVVectorArray {
+ private:
+ const GVArray &array_;
+
+ public:
+ GVVectorArrayForSingleGVArray(const GVArray &array, const int64_t size)
+ : GVVectorArray(array.type(), size), array_(array)
+ {
+ }
+
+ protected:
+ int64_t get_vector_size_impl(const int64_t index) const override;
+ void get_vector_element_impl(const int64_t index,
+ const int64_t index_in_vector,
+ void *r_value) const override;
+
+ bool is_single_vector_impl() const override;
+};
+
+class GVVectorArrayForSingleGSpan : public GVVectorArray {
+ private:
+ const GSpan span_;
+
+ public:
+ GVVectorArrayForSingleGSpan(const GSpan span, const int64_t size)
+ : GVVectorArray(span.type(), size), span_(span)
+ {
+ }
+
+ protected:
+ int64_t get_vector_size_impl(const int64_t UNUSED(index)) const override;
+ void get_vector_element_impl(const int64_t UNUSED(index),
+ const int64_t index_in_vector,
+ void *r_value) const override;
+
+ bool is_single_vector_impl() const override;
+};
+
+template<typename T> class VVectorArrayForGVVectorArray : public VVectorArray<T> {
+ private:
+ const GVVectorArray &vector_array_;
+
+ public:
+ VVectorArrayForGVVectorArray(const GVVectorArray &vector_array)
+ : VVectorArray<T>(vector_array.size()), vector_array_(vector_array)
+ {
+ }
+
+ protected:
+ int64_t get_vector_size_impl(const int64_t index) const override
+ {
+ return vector_array_.get_vector_size(index);
+ }
+
+ T get_vector_element_impl(const int64_t index, const int64_t index_in_vector) const override
+ {
+ T value;
+ vector_array_.get_vector_element(index, index_in_vector, &value);
+ return value;
+ }
+
+ bool is_single_vector_impl() const
+ {
+ return vector_array_.is_single_vector();
+ }
+};
+
+} // namespace blender::fn
diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh
index 0cd1bc262be..b73c41d3f59 100644
--- a/source/blender/functions/FN_multi_function_builder.hh
+++ b/source/blender/functions/FN_multi_function_builder.hh
@@ -38,7 +38,7 @@ namespace blender::fn {
*/
template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunction {
private:
- using FunctionT = std::function<void(IndexMask, VSpan<In1>, MutableSpan<Out1>)>;
+ using FunctionT = std::function<void(IndexMask, const VArray<In1> &, MutableSpan<Out1>)>;
FunctionT function_;
public:
@@ -57,7 +57,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio
template<typename ElementFuncT> static FunctionT create_function(ElementFuncT element_fn)
{
- return [=](IndexMask mask, VSpan<In1> in1, MutableSpan<Out1> out1) {
+ return [=](IndexMask mask, const VArray<In1> &in1, MutableSpan<Out1> out1) {
mask.foreach_index(
[&](int i) { new (static_cast<void *>(&out1[i])) Out1(element_fn(in1[i])); });
};
@@ -65,7 +65,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
{
- VSpan<In1> in1 = params.readonly_single_input<In1>(0);
+ const VArray<In1> &in1 = params.readonly_single_input<In1>(0);
MutableSpan<Out1> out1 = params.uninitialized_single_output<Out1>(1);
function_(mask, in1, out1);
}
@@ -80,7 +80,8 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio
template<typename In1, typename In2, typename Out1>
class CustomMF_SI_SI_SO : public MultiFunction {
private:
- using FunctionT = std::function<void(IndexMask, VSpan<In1>, VSpan<In2>, MutableSpan<Out1>)>;
+ using FunctionT =
+ std::function<void(IndexMask, const VArray<In1> &, const VArray<In2> &, MutableSpan<Out1>)>;
FunctionT function_;
public:
@@ -100,7 +101,10 @@ class CustomMF_SI_SI_SO : public MultiFunction {
template<typename ElementFuncT> static FunctionT create_function(ElementFuncT element_fn)
{
- return [=](IndexMask mask, VSpan<In1> in1, VSpan<In2> in2, MutableSpan<Out1> out1) {
+ return [=](IndexMask mask,
+ const VArray<In1> &in1,
+ const VArray<In2> &in2,
+ MutableSpan<Out1> out1) {
mask.foreach_index(
[&](int i) { new (static_cast<void *>(&out1[i])) Out1(element_fn(in1[i], in2[i])); });
};
@@ -108,8 +112,8 @@ class CustomMF_SI_SI_SO : public MultiFunction {
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
{
- VSpan<In1> in1 = params.readonly_single_input<In1>(0);
- VSpan<In2> in2 = params.readonly_single_input<In2>(1);
+ const VArray<In1> &in1 = params.readonly_single_input<In1>(0);
+ const VArray<In2> &in2 = params.readonly_single_input<In2>(1);
MutableSpan<Out1> out1 = params.uninitialized_single_output<Out1>(2);
function_(mask, in1, in2, out1);
}
@@ -125,8 +129,11 @@ class CustomMF_SI_SI_SO : public MultiFunction {
template<typename In1, typename In2, typename In3, typename Out1>
class CustomMF_SI_SI_SI_SO : public MultiFunction {
private:
- using FunctionT =
- std::function<void(IndexMask, VSpan<In1>, VSpan<In2>, VSpan<In3>, MutableSpan<Out1>)>;
+ using FunctionT = std::function<void(IndexMask,
+ const VArray<In1> &,
+ const VArray<In2> &,
+ const VArray<In3> &,
+ MutableSpan<Out1>)>;
FunctionT function_;
public:
@@ -148,9 +155,9 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction {
template<typename ElementFuncT> static FunctionT create_function(ElementFuncT element_fn)
{
return [=](IndexMask mask,
- VSpan<In1> in1,
- VSpan<In2> in2,
- VSpan<In3> in3,
+ const VArray<In1> &in1,
+ const VArray<In2> &in2,
+ const VArray<In3> &in3,
MutableSpan<Out1> out1) {
mask.foreach_index([&](int i) {
new (static_cast<void *>(&out1[i])) Out1(element_fn(in1[i], in2[i], in3[i]));
@@ -160,9 +167,9 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction {
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
{
- VSpan<In1> in1 = params.readonly_single_input<In1>(0);
- VSpan<In2> in2 = params.readonly_single_input<In2>(1);
- VSpan<In3> in3 = params.readonly_single_input<In3>(2);
+ const VArray<In1> &in1 = params.readonly_single_input<In1>(0);
+ const VArray<In2> &in2 = params.readonly_single_input<In2>(1);
+ const VArray<In3> &in3 = params.readonly_single_input<In3>(2);
MutableSpan<Out1> out1 = params.uninitialized_single_output<Out1>(3);
function_(mask, in1, in2, in3, out1);
}
@@ -179,8 +186,12 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction {
template<typename In1, typename In2, typename In3, typename In4, typename Out1>
class CustomMF_SI_SI_SI_SI_SO : public MultiFunction {
private:
- using FunctionT = std::function<void(
- IndexMask, VSpan<In1>, VSpan<In2>, VSpan<In3>, VSpan<In4>, MutableSpan<Out1>)>;
+ using FunctionT = std::function<void(IndexMask,
+ const VArray<In1> &,
+ const VArray<In2> &,
+ const VArray<In3> &,
+ const VArray<In4> &,
+ MutableSpan<Out1>)>;
FunctionT function_;
public:
@@ -203,10 +214,10 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction {
template<typename ElementFuncT> static FunctionT create_function(ElementFuncT element_fn)
{
return [=](IndexMask mask,
- VSpan<In1> in1,
- VSpan<In2> in2,
- VSpan<In3> in3,
- VSpan<In4> in4,
+ const VArray<In1> &in1,
+ const VArray<In2> &in2,
+ const VArray<In3> &in3,
+ const VArray<In4> &in4,
MutableSpan<Out1> out1) {
mask.foreach_index([&](int i) {
new (static_cast<void *>(&out1[i])) Out1(element_fn(in1[i], in2[i], in3[i], in4[i]));
@@ -216,10 +227,10 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction {
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
{
- VSpan<In1> in1 = params.readonly_single_input<In1>(0);
- VSpan<In2> in2 = params.readonly_single_input<In2>(1);
- VSpan<In3> in3 = params.readonly_single_input<In3>(2);
- VSpan<In4> in4 = params.readonly_single_input<In4>(3);
+ const VArray<In1> &in1 = params.readonly_single_input<In1>(0);
+ const VArray<In2> &in2 = params.readonly_single_input<In2>(1);
+ const VArray<In3> &in3 = params.readonly_single_input<In3>(2);
+ const VArray<In4> &in4 = params.readonly_single_input<In4>(3);
MutableSpan<Out1> out1 = params.uninitialized_single_output<Out1>(4);
function_(mask, in1, in2, in3, in4, out1);
}
@@ -276,7 +287,7 @@ template<typename From, typename To> class CustomMF_Convert : public MultiFuncti
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
{
- VSpan<From> inputs = params.readonly_single_input<From>(0);
+ const VArray<From> &inputs = params.readonly_single_input<From>(0);
MutableSpan<To> outputs = params.uninitialized_single_output<To>(1);
for (int64_t i : mask) {
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh
index ba2d1d0edd3..2d3a8dd650e 100644
--- a/source/blender/functions/FN_multi_function_params.hh
+++ b/source/blender/functions/FN_multi_function_params.hh
@@ -25,18 +25,22 @@
* the function. `MFParams` is then used inside the called function to access the parameters.
*/
+#include "BLI_resource_collector.hh"
+
#include "FN_generic_vector_array.hh"
+#include "FN_generic_virtual_vector_array.hh"
#include "FN_multi_function_signature.hh"
namespace blender::fn {
class MFParamsBuilder {
private:
+ ResourceCollector resources_;
const MFSignature *signature_;
int64_t min_array_size_;
- Vector<GVSpan> virtual_spans_;
+ Vector<const GVArray *> virtual_arrays_;
Vector<GMutableSpan> mutable_spans_;
- Vector<GVArraySpan> virtual_array_spans_;
+ Vector<const GVVectorArray *> virtual_vector_arrays_;
Vector<GVectorArray *> vector_arrays_;
friend class MFParams;
@@ -51,21 +55,32 @@ class MFParamsBuilder {
template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "")
{
- this->add_readonly_single_input(GVSpan::FromSingle(CPPType::get<T>(), value, min_array_size_),
+ this->add_readonly_single_input(resources_.construct<GVArrayForSingleValueRef>(
+ __func__, CPPType::get<T>(), min_array_size_, value),
+ expected_name);
+ }
+ void add_readonly_single_input(const GSpan span, StringRef expected_name = "")
+ {
+ this->add_readonly_single_input(resources_.construct<GVArrayForGSpan>(__func__, span),
expected_name);
}
- void add_readonly_single_input(GVSpan ref, StringRef expected_name = "")
+ void add_readonly_single_input(const GVArray &ref, StringRef expected_name = "")
{
this->assert_current_param_type(MFParamType::ForSingleInput(ref.type()), expected_name);
BLI_assert(ref.size() >= min_array_size_);
- virtual_spans_.append(ref);
+ virtual_arrays_.append(&ref);
}
- void add_readonly_vector_input(GVArraySpan ref, StringRef expected_name = "")
+ void add_readonly_vector_input(const GVectorArray &vector_array, StringRef expected_name = "")
+ {
+ this->add_readonly_vector_input(
+ resources_.construct<GVVectorArrayForGVectorArray>(__func__, vector_array), expected_name);
+ }
+ void add_readonly_vector_input(const GVVectorArray &ref, StringRef expected_name = "")
{
this->assert_current_param_type(MFParamType::ForVectorInput(ref.type()), expected_name);
BLI_assert(ref.size() >= min_array_size_);
- virtual_array_spans_.append(ref);
+ virtual_vector_arrays_.append(&ref);
}
template<typename T> void add_uninitialized_single_output(T *value, StringRef expected_name = "")
@@ -121,6 +136,11 @@ class MFParamsBuilder {
return *vector_arrays_[data_index];
}
+ ResourceCollector &resources()
+ {
+ return resources_;
+ }
+
private:
void assert_current_param_type(MFParamType param_type, StringRef expected_name = "")
{
@@ -140,7 +160,7 @@ class MFParamsBuilder {
int current_param_index() const
{
- return virtual_spans_.size() + mutable_spans_.size() + virtual_array_spans_.size() +
+ return virtual_arrays_.size() + mutable_spans_.size() + virtual_vector_arrays_.size() +
vector_arrays_.size();
}
};
@@ -154,15 +174,16 @@ class MFParams {
{
}
- template<typename T> VSpan<T> readonly_single_input(int param_index, StringRef name = "")
+ template<typename T> const VArray<T> &readonly_single_input(int param_index, StringRef name = "")
{
- return this->readonly_single_input(param_index, name).typed<T>();
+ const GVArray &array = this->readonly_single_input(param_index, name);
+ return builder_->resources_.construct<VArrayForGVArray<T>>(__func__, array);
}
- GVSpan readonly_single_input(int param_index, StringRef name = "")
+ 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_spans_[data_index];
+ return *builder_->virtual_arrays_[data_index];
}
template<typename T>
@@ -177,20 +198,23 @@ class MFParams {
return builder_->mutable_spans_[data_index];
}
- template<typename T> VArraySpan<T> readonly_vector_input(int param_index, StringRef name = "")
+ template<typename T>
+ const VVectorArray<T> &readonly_vector_input(int param_index, StringRef name = "")
{
- return this->readonly_vector_input(param_index, name).typed<T>();
+ const GVVectorArray &vector_array = this->readonly_vector_input(param_index, name);
+ return builder_->resources_.construct<VVectorArrayForGVVectorArray<T>>(__func__, vector_array);
}
- GVArraySpan readonly_vector_input(int param_index, StringRef name = "")
+ const GVVectorArray &readonly_vector_input(int param_index, StringRef name = "")
{
this->assert_correct_param(param_index, name, MFParamType::VectorInput);
int data_index = builder_->signature_->data_index(param_index);
- return builder_->virtual_array_spans_[data_index];
+ return *builder_->virtual_vector_arrays_[data_index];
}
- template<typename T> GVectorArrayRef<T> vector_output(int param_index, StringRef name = "")
+ template<typename T>
+ GVectorArray_TypedMutableRef<T> vector_output(int param_index, StringRef name = "")
{
- return this->vector_output(param_index, name).typed<T>();
+ return {this->vector_output(param_index, name)};
}
GVectorArray &vector_output(int param_index, StringRef name = "")
{
@@ -210,9 +234,10 @@ class MFParams {
return builder_->mutable_spans_[data_index];
}
- template<typename T> GVectorArrayRef<T> vector_mutable(int param_index, StringRef name = "")
+ template<typename T>
+ GVectorArray_TypedMutableRef<T> vector_mutable(int param_index, StringRef name = "")
{
- return this->vector_mutable(param_index, name).typed<T>();
+ return {this->vector_mutable(param_index, name)};
}
GVectorArray &vector_mutable(int param_index, StringRef name = "")
{
diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh
index ef51ddbaf24..e05ea1c2578 100644
--- a/source/blender/functions/FN_multi_function_signature.hh
+++ b/source/blender/functions/FN_multi_function_signature.hh
@@ -46,8 +46,8 @@ class MFSignatureBuilder {
private:
MFSignature &data_;
int span_count_ = 0;
- int virtual_span_count_ = 0;
- int virtual_array_span_count_ = 0;
+ int virtual_array_count_ = 0;
+ int virtual_vector_array_count_ = 0;
int vector_array_count_ = 0;
public:
@@ -83,10 +83,10 @@ class MFSignatureBuilder {
switch (data_type.category()) {
case MFDataType::Single:
- data_.param_data_indices.append(virtual_span_count_++);
+ data_.param_data_indices.append(virtual_array_count_++);
break;
case MFDataType::Vector:
- data_.param_data_indices.append(virtual_array_span_count_++);
+ data_.param_data_indices.append(virtual_vector_array_count_++);
break;
}
}
diff --git a/source/blender/functions/FN_spans.hh b/source/blender/functions/FN_spans.hh
deleted file mode 100644
index 41c930581a4..00000000000
--- a/source/blender/functions/FN_spans.hh
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-/** \file
- * \ingroup fn
- *
- * This file implements multiple variants of a span for different use cases. There are two
- * requirements of the function system that require span implementations other from
- * blender::Span<T>.
- * 1. The function system works with a run-time type system (see `CPPType`). Therefore, it has to
- * deal with types in a generic way. The type of a Span<T> has to be known at compile time.
- * 2. Span<T> expects an underlying memory buffer that is as large as the span. However, sometimes
- * we can save some memory and processing when we know that all elements are the same.
- *
- * The first requirement is solved with generic spans, which use the "G" prefix. Those
- * store a CPPType instance to keep track of the type that is currently stored.
- *
- * The second requirement is solved with virtual spans. A virtual span behaves like a normal span,
- * but it might not be backed up by an actual array. Elements in a virtual span are always
- * immutable.
- *
- * Different use cases require different combinations of these properties and therefore use
- * different data structures.
- */
-
-#include "BLI_span.hh"
-
-#include "FN_cpp_type.hh"
-
-namespace blender::fn {
-
-/**
- * A generic span. It behaves just like a blender::Span<T>, but the type is only known at run-time.
- */
-class GSpan {
- private:
- const CPPType *type_;
- const void *data_;
- int64_t size_;
-
- public:
- GSpan(const CPPType &type, const void *buffer, int64_t size)
- : type_(&type), data_(buffer), size_(size)
- {
- BLI_assert(size >= 0);
- BLI_assert(buffer != nullptr || size == 0);
- BLI_assert(type.pointer_has_valid_alignment(buffer));
- }
-
- GSpan(const CPPType &type) : GSpan(type, nullptr, 0)
- {
- }
-
- template<typename T>
- GSpan(Span<T> array)
- : GSpan(CPPType::get<T>(), static_cast<const void *>(array.data()), array.size())
- {
- }
-
- const CPPType &type() const
- {
- return *type_;
- }
-
- bool is_empty() const
- {
- return size_ == 0;
- }
-
- int64_t size() const
- {
- return size_;
- }
-
- const void *data() const
- {
- return data_;
- }
-
- const void *operator[](int64_t index) const
- {
- BLI_assert(index < size_);
- return POINTER_OFFSET(data_, type_->size() * index);
- }
-
- template<typename T> Span<T> typed() const
- {
- BLI_assert(type_->is<T>());
- return Span<T>(static_cast<const T *>(data_), size_);
- }
-};
-
-/**
- * A generic mutable span. It behaves just like a blender::MutableSpan<T>, but the type is only
- * known at run-time.
- */
-class GMutableSpan {
- private:
- const CPPType *type_;
- void *data_;
- int64_t size_;
-
- public:
- GMutableSpan(const CPPType &type, void *buffer, int64_t size)
- : type_(&type), data_(buffer), size_(size)
- {
- BLI_assert(size >= 0);
- BLI_assert(buffer != nullptr || size == 0);
- BLI_assert(type.pointer_has_valid_alignment(buffer));
- }
-
- GMutableSpan(const CPPType &type) : GMutableSpan(type, nullptr, 0)
- {
- }
-
- template<typename T>
- GMutableSpan(MutableSpan<T> array)
- : GMutableSpan(CPPType::get<T>(), static_cast<void *>(array.begin()), array.size())
- {
- }
-
- operator GSpan() const
- {
- return GSpan(*type_, data_, size_);
- }
-
- const CPPType &type() const
- {
- return *type_;
- }
-
- bool is_empty() const
- {
- return size_ == 0;
- }
-
- int64_t size() const
- {
- return size_;
- }
-
- void *data()
- {
- return data_;
- }
-
- void *operator[](int64_t index)
- {
- BLI_assert(index >= 0);
- BLI_assert(index < size_);
- return POINTER_OFFSET(data_, type_->size() * index);
- }
-
- void *operator[](int64_t index) const
- {
- BLI_assert(index >= 0);
- BLI_assert(index < size_);
- return POINTER_OFFSET(data_, type_->size() * index);
- }
-
- template<typename T> MutableSpan<T> typed()
- {
- BLI_assert(type_->is<T>());
- return MutableSpan<T>(static_cast<T *>(data_), size_);
- }
-};
-
-enum class VSpanCategory {
- Single,
- FullArray,
- FullPointerArray,
-};
-
-template<typename T> struct VSpanBase {
- protected:
- int64_t virtual_size_;
- VSpanCategory category_;
- union {
- struct {
- const T *data;
- } single;
- struct {
- const T *data;
- } full_array;
- struct {
- const T *const *data;
- } full_pointer_array;
- } data_;
-
- public:
- bool is_single_element() const
- {
- switch (category_) {
- case VSpanCategory::Single:
- return true;
- case VSpanCategory::FullArray:
- return virtual_size_ == 1;
- case VSpanCategory::FullPointerArray:
- return virtual_size_ == 1;
- }
- BLI_assert(false);
- return false;
- }
-
- bool is_full_array() const
- {
- switch (category_) {
- case VSpanCategory::Single:
- return virtual_size_ == 1;
- case VSpanCategory::FullArray:
- return true;
- case VSpanCategory::FullPointerArray:
- return virtual_size_ <= 1;
- }
- BLI_assert(false);
- return false;
- }
-
- bool is_empty() const
- {
- return this->virtual_size_ == 0;
- }
-
- int64_t size() const
- {
- return this->virtual_size_;
- }
-};
-
-BLI_STATIC_ASSERT((sizeof(VSpanBase<void>) == sizeof(VSpanBase<AlignedBuffer<64, 64>>)),
- "should not depend on the size of the type");
-
-/**
- * A virtual span. It behaves like a blender::Span<T>, but might not be backed up by an actual
- * array.
- */
-template<typename T> class VSpan : public VSpanBase<T> {
- friend class GVSpan;
-
- VSpan(const VSpanBase<void> &values)
- {
- memcpy(this, &values, sizeof(VSpanBase<void>));
- }
-
- public:
- VSpan()
- {
- this->virtual_size_ = 0;
- this->category_ = VSpanCategory::FullArray;
- this->data_.full_array.data = nullptr;
- }
-
- VSpan(Span<T> values)
- {
- this->virtual_size_ = values.size();
- this->category_ = VSpanCategory::FullArray;
- this->data_.full_array.data = values.begin();
- }
-
- VSpan(MutableSpan<T> values) : VSpan(Span<T>(values))
- {
- }
-
- VSpan(Span<const T *> values)
- {
- this->virtual_size_ = values.size();
- this->category_ = VSpanCategory::FullPointerArray;
- this->data_.full_pointer_array.data = values.begin();
- }
-
- static VSpan FromSingle(const T *value, int64_t virtual_size)
- {
- VSpan ref;
- ref.virtual_size_ = virtual_size;
- ref.category_ = VSpanCategory::Single;
- ref.data_.single.data = value;
- return ref;
- }
-
- const T &operator[](int64_t index) const
- {
- BLI_assert(index >= 0);
- BLI_assert(index < this->virtual_size_);
- switch (this->category_) {
- case VSpanCategory::Single:
- return *this->data_.single.data;
- case VSpanCategory::FullArray:
- return this->data_.full_array.data[index];
- case VSpanCategory::FullPointerArray:
- return *this->data_.full_pointer_array.data[index];
- }
- BLI_assert(false);
- return *this->data_.single.data;
- }
-
- const T &as_single_element() const
- {
- BLI_assert(this->is_single_element());
- return (*this)[0];
- }
-
- Span<T> as_full_array() const
- {
- BLI_assert(this->is_full_array());
- if (this->virtual_size_ == 0) {
- return Span<T>();
- }
- const T *data = &(*this)[0];
- return Span<T>(data, this->virtual_size_);
- }
-};
-
-/**
- * A generic virtual span. It behaves like a blender::Span<T>, but the type is only known at
- * run-time and it might not be backed up by an actual array.
- */
-class GVSpan : public VSpanBase<void> {
- private:
- const CPPType *type_;
-
- GVSpan() = default;
-
- public:
- GVSpan(const CPPType &type)
- {
- this->type_ = &type;
- this->virtual_size_ = 0;
- this->category_ = VSpanCategory::FullArray;
- this->data_.full_array.data = nullptr;
- }
-
- GVSpan(GSpan values)
- {
- this->type_ = &values.type();
- this->virtual_size_ = values.size();
- this->category_ = VSpanCategory::FullArray;
- this->data_.full_array.data = values.data();
- }
-
- GVSpan(GMutableSpan values) : GVSpan(GSpan(values))
- {
- }
-
- template<typename T> GVSpan(const VSpanBase<T> &values)
- {
- this->type_ = &CPPType::get<T>();
- memcpy(this, &values, sizeof(VSpanBase<void>));
- }
-
- template<typename T> GVSpan(Span<T> values) : GVSpan(GSpan(values))
- {
- }
-
- template<typename T> GVSpan(MutableSpan<T> values) : GVSpan(GSpan(values))
- {
- }
-
- static GVSpan FromSingle(const CPPType &type, const void *value, int64_t virtual_size)
- {
- GVSpan ref;
- ref.type_ = &type;
- ref.virtual_size_ = virtual_size;
- ref.category_ = VSpanCategory::Single;
- ref.data_.single.data = value;
- return ref;
- }
-
- static GVSpan FromSingleWithMaxSize(const CPPType &type, const void *value)
- {
- return GVSpan::FromSingle(type, value, INT64_MAX);
- }
-
- static GVSpan FromDefault(const CPPType &type)
- {
- return GVSpan::FromSingleWithMaxSize(type, type.default_value());
- }
-
- static GVSpan FromFullPointerArray(const CPPType &type, const void *const *values, int64_t size)
- {
- GVSpan ref;
- ref.type_ = &type;
- ref.virtual_size_ = size;
- ref.category_ = VSpanCategory::FullPointerArray;
- ref.data_.full_pointer_array.data = values;
- return ref;
- }
-
- const CPPType &type() const
- {
- return *this->type_;
- }
-
- const void *operator[](int64_t index) const
- {
- BLI_assert(index >= 0);
- BLI_assert(index < this->virtual_size_);
- switch (this->category_) {
- case VSpanCategory::Single:
- return this->data_.single.data;
- case VSpanCategory::FullArray:
- return POINTER_OFFSET(this->data_.full_array.data, index * type_->size());
- case VSpanCategory::FullPointerArray:
- return this->data_.full_pointer_array.data[index];
- }
- BLI_assert(false);
- return this->data_.single.data;
- }
-
- template<typename T> VSpan<T> typed() const
- {
- BLI_assert(type_->is<T>());
- return VSpan<T>(*this);
- }
-
- const void *as_single_element() const
- {
- BLI_assert(this->is_single_element());
- return (*this)[0];
- }
-
- GSpan as_full_array() const
- {
- BLI_assert(this->is_full_array());
- if (this->virtual_size_ == 0) {
- return GSpan(*this->type_);
- }
- const void *data = (*this)[0];
- return GSpan(*this->type_, data, this->virtual_size_);
- }
-
- void materialize_to_uninitialized(void *dst) const
- {
- this->materialize_to_uninitialized(IndexRange(virtual_size_), dst);
- }
-
- void materialize_to_uninitialized(IndexMask mask, void *dst) const
- {
- BLI_assert(this->size() >= mask.min_array_size());
-
- int64_t element_size = type_->size();
- for (int64_t i : mask) {
- type_->copy_to_uninitialized((*this)[i], POINTER_OFFSET(dst, element_size * i));
- }
- }
-};
-
-} // namespace blender::fn
diff --git a/source/blender/functions/intern/generic_vector_array.cc b/source/blender/functions/intern/generic_vector_array.cc
new file mode 100644
index 00000000000..b3c5517cc43
--- /dev/null
+++ b/source/blender/functions/intern/generic_vector_array.cc
@@ -0,0 +1,104 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "FN_generic_vector_array.hh"
+#include "FN_multi_function_params.hh"
+#include "FN_multi_function_signature.hh"
+
+namespace blender::fn {
+
+GVectorArray::GVectorArray(const CPPType &type, const int64_t array_size)
+ : type_(type), element_size_(type.size()), items_(array_size)
+{
+}
+
+GVectorArray::~GVectorArray()
+{
+ if (type_.is_trivially_destructible()) {
+ return;
+ }
+ for (Item &item : items_) {
+ type_.destruct_n(item.start, item.length);
+ }
+}
+
+void GVectorArray::append(const int64_t index, const void *value)
+{
+ Item &item = items_[index];
+ if (item.length == item.capacity) {
+ this->realloc_to_at_least(item, item.capacity + 1);
+ }
+
+ void *dst = POINTER_OFFSET(item.start, element_size_ * item.length);
+ type_.copy_to_uninitialized(value, dst);
+ item.length++;
+}
+
+void GVectorArray::extend(const int64_t index, const GVArray &values)
+{
+ BLI_assert(values.type() == type_);
+ for (const int i : IndexRange(values.size())) {
+ BUFFER_FOR_CPP_TYPE_VALUE(type_, buffer);
+ values.get(i, buffer);
+ this->append(index, buffer);
+ type_.destruct(buffer);
+ }
+}
+
+void GVectorArray::extend(const int64_t index, const GSpan values)
+{
+ GVArrayForGSpan varray{values};
+ this->extend(index, varray);
+}
+
+void GVectorArray::extend(IndexMask mask, const GVVectorArray &values)
+{
+ for (const int i : mask) {
+ GVArrayForGVVectorArrayIndex array{values, i};
+ this->extend(i, array);
+ }
+}
+
+void GVectorArray::extend(IndexMask mask, const GVectorArray &values)
+{
+ GVVectorArrayForGVectorArray virtual_values{values};
+ this->extend(mask, virtual_values);
+}
+
+GMutableSpan GVectorArray::operator[](const int64_t index)
+{
+ Item &item = items_[index];
+ return GMutableSpan{type_, item.start, item.length};
+}
+
+GSpan GVectorArray::operator[](const int64_t index) const
+{
+ const Item &item = items_[index];
+ return GSpan{type_, item.start, item.length};
+}
+
+void GVectorArray::realloc_to_at_least(Item &item, int64_t min_capacity)
+{
+ const int64_t new_capacity = std::max(min_capacity, item.length * 2);
+
+ void *new_buffer = allocator_.allocate(element_size_ * new_capacity, type_.alignment());
+ type_.relocate_to_initialized_n(item.start, new_buffer, item.length);
+
+ item.start = new_buffer;
+ item.capacity = new_capacity;
+}
+
+} // namespace blender::fn
diff --git a/source/blender/functions/intern/generic_virtual_array.cc b/source/blender/functions/intern/generic_virtual_array.cc
new file mode 100644
index 00000000000..9380eb257b2
--- /dev/null
+++ b/source/blender/functions/intern/generic_virtual_array.cc
@@ -0,0 +1,107 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "FN_generic_virtual_array.hh"
+
+namespace blender::fn {
+
+void GVArray::materialize_to_uninitialized(const IndexMask mask, void *dst) const
+{
+ for (const int64_t i : mask) {
+ void *elem_dst = POINTER_OFFSET(dst, type_->size() * i);
+ this->get_to_uninitialized(i, elem_dst);
+ }
+}
+
+void GVArray::get_impl(const int64_t index, void *r_value) const
+{
+ type_->destruct(r_value);
+ this->get_to_uninitialized_impl(index, r_value);
+}
+
+bool GVArray::is_span_impl() const
+{
+ return false;
+}
+
+GSpan GVArray::get_span_impl() const
+{
+ BLI_assert(false);
+ return GSpan(*type_);
+}
+
+bool GVArray::is_single_impl() const
+{
+ return false;
+}
+
+void GVArray::get_single_impl(void *UNUSED(r_value)) const
+{
+ BLI_assert(false);
+}
+
+void GVArrayForGSpan::get_impl(const int64_t index, void *r_value) const
+{
+ type_->copy_to_initialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
+}
+
+void GVArrayForGSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const
+{
+ type_->copy_to_uninitialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
+}
+
+bool GVArrayForGSpan::is_span_impl() const
+{
+ return true;
+}
+
+GSpan GVArrayForGSpan::get_span_impl() const
+{
+ return GSpan(*type_, data_, size_);
+}
+
+void GVArrayForSingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const
+{
+ type_->copy_to_initialized(value_, r_value);
+}
+
+void GVArrayForSingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index),
+ void *r_value) const
+{
+ type_->copy_to_uninitialized(value_, r_value);
+}
+
+bool GVArrayForSingleValueRef::is_span_impl() const
+{
+ return size_ == 1;
+}
+
+GSpan GVArrayForSingleValueRef::get_span_impl() const
+{
+ return GSpan{*type_, value_, 1};
+}
+
+bool GVArrayForSingleValueRef::is_single_impl() const
+{
+ return true;
+}
+
+void GVArrayForSingleValueRef::get_single_impl(void *r_value) const
+{
+ type_->copy_to_initialized(value_, r_value);
+}
+
+} // namespace blender::fn
diff --git a/source/blender/functions/intern/generic_virtual_vector_array.cc b/source/blender/functions/intern/generic_virtual_vector_array.cc
new file mode 100644
index 00000000000..f6504cee41e
--- /dev/null
+++ b/source/blender/functions/intern/generic_virtual_vector_array.cc
@@ -0,0 +1,67 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "FN_generic_virtual_vector_array.hh"
+
+namespace blender::fn {
+
+void GVArrayForGVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const
+{
+ vector_array_.get_vector_element(index_, index_in_vector, r_value);
+}
+
+void GVArrayForGVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector,
+ void *r_value) const
+{
+ type_->construct_default(r_value);
+ vector_array_.get_vector_element(index_, index_in_vector, r_value);
+}
+
+int64_t GVVectorArrayForSingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const
+{
+ return array_.size();
+}
+
+void GVVectorArrayForSingleGVArray::get_vector_element_impl(const int64_t UNUSED(index),
+ const int64_t index_in_vector,
+ void *r_value) const
+{
+ array_.get(index_in_vector, r_value);
+}
+
+bool GVVectorArrayForSingleGVArray::is_single_vector_impl() const
+{
+ return true;
+}
+
+int64_t GVVectorArrayForSingleGSpan::get_vector_size_impl(const int64_t UNUSED(index)) const
+{
+ return span_.size();
+}
+
+void GVVectorArrayForSingleGSpan::get_vector_element_impl(const int64_t UNUSED(index),
+ const int64_t index_in_vector,
+ void *r_value) const
+{
+ type_->copy_to_initialized(span_[index_in_vector], r_value);
+}
+
+bool GVVectorArrayForSingleGSpan::is_single_vector_impl() const
+{
+ return true;
+}
+
+} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_network_evaluation.cc b/source/blender/functions/intern/multi_function_network_evaluation.cc
index 5a37a45908f..98500a350ae 100644
--- a/source/blender/functions/intern/multi_function_network_evaluation.cc
+++ b/source/blender/functions/intern/multi_function_network_evaluation.cc
@@ -37,6 +37,7 @@
#include "FN_multi_function_network_evaluation.hh"
+#include "BLI_resource_collector.hh"
#include "BLI_stack.hh"
namespace blender::fn {
@@ -62,16 +63,20 @@ class MFNetworkEvaluationStorage {
~MFNetworkEvaluationStorage();
/* Add the values that have been provided by the caller of the multi-function network. */
- void add_single_input_from_caller(const MFOutputSocket &socket, GVSpan virtual_span);
- void add_vector_input_from_caller(const MFOutputSocket &socket, GVArraySpan virtual_array_span);
+ void add_single_input_from_caller(const MFOutputSocket &socket, const GVArray &virtual_array);
+ void add_vector_input_from_caller(const MFOutputSocket &socket,
+ const GVVectorArray &virtual_vector_array);
void add_single_output_from_caller(const MFOutputSocket &socket, GMutableSpan span);
void add_vector_output_from_caller(const MFOutputSocket &socket, GVectorArray &vector_array);
/* Get input buffers for function node evaluations. */
- GVSpan get_single_input__full(const MFInputSocket &socket);
- GVSpan get_single_input__single(const MFInputSocket &socket);
- GVArraySpan get_vector_input__full(const MFInputSocket &socket);
- GVArraySpan get_vector_input__single(const MFInputSocket &socket);
+ const GVArray &get_single_input__full(const MFInputSocket &socket, ResourceCollector &resources);
+ const GVArray &get_single_input__single(const MFInputSocket &socket,
+ ResourceCollector &resources);
+ const GVVectorArray &get_vector_input__full(const MFInputSocket &socket,
+ ResourceCollector &resources);
+ const GVVectorArray &get_vector_input__single(const MFInputSocket &socket,
+ ResourceCollector &resources);
/* Get output buffers for function node evaluations. */
GMutableSpan get_single_output__full(const MFOutputSocket &socket);
@@ -80,12 +85,18 @@ class MFNetworkEvaluationStorage {
GVectorArray &get_vector_output__single(const MFOutputSocket &socket);
/* Get mutable buffers for function node evaluations. */
- GMutableSpan get_mutable_single__full(const MFInputSocket &input, const MFOutputSocket &output);
+ GMutableSpan get_mutable_single__full(const MFInputSocket &input,
+ const MFOutputSocket &output,
+ ResourceCollector &resources);
GMutableSpan get_mutable_single__single(const MFInputSocket &input,
- const MFOutputSocket &output);
- GVectorArray &get_mutable_vector__full(const MFInputSocket &input, const MFOutputSocket &output);
+ const MFOutputSocket &output,
+ ResourceCollector &resources);
+ GVectorArray &get_mutable_vector__full(const MFInputSocket &input,
+ const MFOutputSocket &output,
+ ResourceCollector &resources);
GVectorArray &get_mutable_vector__single(const MFInputSocket &input,
- const MFOutputSocket &output);
+ const MFOutputSocket &output,
+ ResourceCollector &resources);
/* Mark a node as being done with evaluation. This might free temporary buffers that are no
* longer needed. */
@@ -160,12 +171,12 @@ BLI_NOINLINE void MFNetworkEvaluator::copy_inputs_to_storage(MFParams params,
const MFOutputSocket &socket = *inputs_[input_index];
switch (socket.data_type().category()) {
case MFDataType::Single: {
- GVSpan input_list = params.readonly_single_input(param_index);
+ const GVArray &input_list = params.readonly_single_input(param_index);
storage.add_single_input_from_caller(socket, input_list);
break;
}
case MFDataType::Vector: {
- GVArraySpan input_list_list = params.readonly_vector_input(param_index);
+ const GVVectorArray &input_list_list = params.readonly_vector_input(param_index);
storage.add_vector_input_from_caller(socket, input_list_list);
break;
}
@@ -255,6 +266,7 @@ BLI_NOINLINE void MFNetworkEvaluator::evaluate_function(MFContext &global_contex
const MFFunctionNode &function_node,
Storage &storage) const
{
+
const MultiFunction &function = function_node.function();
// std::cout << "Function: " << function.name() << "\n";
@@ -262,19 +274,20 @@ BLI_NOINLINE void MFNetworkEvaluator::evaluate_function(MFContext &global_contex
/* The function output would be the same for all elements. Therefore, it is enough to call the
* function only on a single element. This can avoid many duplicate computations. */
MFParamsBuilder params{function, 1};
+ ResourceCollector &resources = params.resources();
for (int param_index : function.param_indices()) {
MFParamType param_type = function.param_type(param_index);
switch (param_type.category()) {
case MFParamType::SingleInput: {
const MFInputSocket &socket = function_node.input_for_param(param_index);
- GVSpan values = storage.get_single_input__single(socket);
+ const GVArray &values = storage.get_single_input__single(socket, resources);
params.add_readonly_single_input(values);
break;
}
case MFParamType::VectorInput: {
const MFInputSocket &socket = function_node.input_for_param(param_index);
- GVArraySpan values = storage.get_vector_input__single(socket);
+ const GVVectorArray &values = storage.get_vector_input__single(socket, resources);
params.add_readonly_vector_input(values);
break;
}
@@ -293,14 +306,14 @@ BLI_NOINLINE void MFNetworkEvaluator::evaluate_function(MFContext &global_contex
case MFParamType::SingleMutable: {
const MFInputSocket &input = function_node.input_for_param(param_index);
const MFOutputSocket &output = function_node.output_for_param(param_index);
- GMutableSpan values = storage.get_mutable_single__single(input, output);
+ GMutableSpan values = storage.get_mutable_single__single(input, output, resources);
params.add_single_mutable(values);
break;
}
case MFParamType::VectorMutable: {
const MFInputSocket &input = function_node.input_for_param(param_index);
const MFOutputSocket &output = function_node.output_for_param(param_index);
- GVectorArray &values = storage.get_mutable_vector__single(input, output);
+ GVectorArray &values = storage.get_mutable_vector__single(input, output, resources);
params.add_vector_mutable(values);
break;
}
@@ -311,19 +324,20 @@ BLI_NOINLINE void MFNetworkEvaluator::evaluate_function(MFContext &global_contex
}
else {
MFParamsBuilder params{function, storage.mask().min_array_size()};
+ ResourceCollector &resources = params.resources();
for (int param_index : function.param_indices()) {
MFParamType param_type = function.param_type(param_index);
switch (param_type.category()) {
case MFParamType::SingleInput: {
const MFInputSocket &socket = function_node.input_for_param(param_index);
- GVSpan values = storage.get_single_input__full(socket);
+ const GVArray &values = storage.get_single_input__full(socket, resources);
params.add_readonly_single_input(values);
break;
}
case MFParamType::VectorInput: {
const MFInputSocket &socket = function_node.input_for_param(param_index);
- GVArraySpan values = storage.get_vector_input__full(socket);
+ const GVVectorArray &values = storage.get_vector_input__full(socket, resources);
params.add_readonly_vector_input(values);
break;
}
@@ -342,14 +356,14 @@ BLI_NOINLINE void MFNetworkEvaluator::evaluate_function(MFContext &global_contex
case MFParamType::SingleMutable: {
const MFInputSocket &input = function_node.input_for_param(param_index);
const MFOutputSocket &output = function_node.output_for_param(param_index);
- GMutableSpan values = storage.get_mutable_single__full(input, output);
+ GMutableSpan values = storage.get_mutable_single__full(input, output, resources);
params.add_single_mutable(values);
break;
}
case MFParamType::VectorMutable: {
const MFInputSocket &input = function_node.input_for_param(param_index);
const MFOutputSocket &output = function_node.output_for_param(param_index);
- GVectorArray &values = storage.get_mutable_vector__full(input, output);
+ GVectorArray &values = storage.get_mutable_vector__full(input, output, resources);
params.add_vector_mutable(values);
break;
}
@@ -383,18 +397,19 @@ bool MFNetworkEvaluator::can_do_single_value_evaluation(const MFFunctionNode &fu
BLI_NOINLINE void MFNetworkEvaluator::initialize_remaining_outputs(
MFParams params, Storage &storage, Span<const MFInputSocket *> remaining_outputs) const
{
+ ResourceCollector resources;
for (const MFInputSocket *socket : remaining_outputs) {
int param_index = inputs_.size() + outputs_.first_index_of(socket);
switch (socket->data_type().category()) {
case MFDataType::Single: {
- GVSpan values = storage.get_single_input__full(*socket);
+ const GVArray &values = storage.get_single_input__full(*socket, resources);
GMutableSpan output_values = params.uninitialized_single_output(param_index);
values.materialize_to_uninitialized(storage.mask(), output_values.data());
break;
}
case MFDataType::Vector: {
- GVArraySpan values = storage.get_vector_input__full(*socket);
+ const GVVectorArray &values = storage.get_vector_input__full(*socket, resources);
GVectorArray &output_values = params.vector_output(param_index);
output_values.extend(storage.mask(), values);
break;
@@ -425,20 +440,21 @@ struct Value {
};
struct InputSingleValue : public Value {
- /** This span has been provided by the code that called the multi-function network. */
- GVSpan virtual_span;
+ /** This virtual array has been provided by the code that called the multi-function network. */
+ const GVArray &virtual_array;
- InputSingleValue(GVSpan virtual_span) : Value(ValueType::InputSingle), virtual_span(virtual_span)
+ InputSingleValue(const GVArray &virtual_array)
+ : Value(ValueType::InputSingle), virtual_array(virtual_array)
{
}
};
struct InputVectorValue : public Value {
- /** This span has been provided by the code that called the multi-function network. */
- GVArraySpan virtual_array_span;
+ /** This virtual vector has been provided by the code that called the multi-function network. */
+ const GVVectorArray &virtual_vector_array;
- InputVectorValue(GVArraySpan virtual_array_span)
- : Value(ValueType::InputVector), virtual_array_span(virtual_array_span)
+ InputVectorValue(const GVVectorArray &virtual_vector_array)
+ : Value(ValueType::InputVector), virtual_vector_array(virtual_vector_array)
{
}
};
@@ -564,9 +580,9 @@ bool MFNetworkEvaluationStorage::is_same_value_for_every_index(const MFOutputSoc
case ValueType::OwnVector:
return static_cast<OwnVectorValue *>(any_value)->vector_array->size() == 1;
case ValueType::InputSingle:
- return static_cast<InputSingleValue *>(any_value)->virtual_span.is_single_element();
+ return static_cast<InputSingleValue *>(any_value)->virtual_array.is_single();
case ValueType::InputVector:
- return static_cast<InputVectorValue *>(any_value)->virtual_array_span.is_single_array();
+ return static_cast<InputVectorValue *>(any_value)->virtual_vector_array.is_single_vector();
case ValueType::OutputSingle:
return static_cast<OutputSingleValue *>(any_value)->span.size() == 1;
case ValueType::OutputVector:
@@ -658,22 +674,22 @@ void MFNetworkEvaluationStorage::finish_input_socket(const MFInputSocket &socket
}
void MFNetworkEvaluationStorage::add_single_input_from_caller(const MFOutputSocket &socket,
- GVSpan virtual_span)
+ const GVArray &virtual_array)
{
BLI_assert(value_per_output_id_[socket.id()] == nullptr);
- BLI_assert(virtual_span.size() >= min_array_size_);
+ BLI_assert(virtual_array.size() >= min_array_size_);
- auto *value = allocator_.construct<InputSingleValue>(virtual_span).release();
+ auto *value = allocator_.construct<InputSingleValue>(virtual_array).release();
value_per_output_id_[socket.id()] = value;
}
-void MFNetworkEvaluationStorage::add_vector_input_from_caller(const MFOutputSocket &socket,
- GVArraySpan virtual_array_span)
+void MFNetworkEvaluationStorage::add_vector_input_from_caller(
+ const MFOutputSocket &socket, const GVVectorArray &virtual_vector_array)
{
BLI_assert(value_per_output_id_[socket.id()] == nullptr);
- BLI_assert(virtual_array_span.size() >= min_array_size_);
+ BLI_assert(virtual_vector_array.size() >= min_array_size_);
- auto *value = allocator_.construct<InputVectorValue>(virtual_array_span).release();
+ auto *value = allocator_.construct<InputVectorValue>(virtual_vector_array).release();
value_per_output_id_[socket.id()] = value;
}
@@ -776,7 +792,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_vector_output__single(const MFOutp
}
GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__full(const MFInputSocket &input,
- const MFOutputSocket &output)
+ const MFOutputSocket &output,
+ ResourceCollector &resources)
{
const MFOutputSocket &from = *input.origin();
const MFOutputSocket &to = output;
@@ -790,8 +807,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__full(const MFInputS
if (to_any_value != nullptr) {
BLI_assert(to_any_value->type == ValueType::OutputSingle);
GMutableSpan span = static_cast<OutputSingleValue *>(to_any_value)->span;
- GVSpan virtual_span = this->get_single_input__full(input);
- virtual_span.materialize_to_uninitialized(mask_, span.data());
+ const GVArray &virtual_array = this->get_single_input__full(input, resources);
+ virtual_array.materialize_to_uninitialized(mask_, span.data());
return span;
}
@@ -805,10 +822,10 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__full(const MFInputS
}
}
- GVSpan virtual_span = this->get_single_input__full(input);
+ const GVArray &virtual_array = this->get_single_input__full(input, resources);
void *new_buffer = MEM_mallocN_aligned(min_array_size_ * type.size(), type.alignment(), AT);
GMutableSpan new_array_ref(type, new_buffer, min_array_size_);
- virtual_span.materialize_to_uninitialized(mask_, new_array_ref.data());
+ virtual_array.materialize_to_uninitialized(mask_, new_array_ref.data());
OwnSingleValue *new_value =
allocator_.construct<OwnSingleValue>(new_array_ref, to.targets().size(), false).release();
@@ -817,7 +834,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__full(const MFInputS
}
GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__single(const MFInputSocket &input,
- const MFOutputSocket &output)
+ const MFOutputSocket &output,
+ ResourceCollector &resources)
{
const MFOutputSocket &from = *input.origin();
const MFOutputSocket &to = output;
@@ -832,8 +850,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__single(const MFInpu
BLI_assert(to_any_value->type == ValueType::OutputSingle);
GMutableSpan span = static_cast<OutputSingleValue *>(to_any_value)->span;
BLI_assert(span.size() == 1);
- GVSpan virtual_span = this->get_single_input__single(input);
- type.copy_to_uninitialized(virtual_span.as_single_element(), span[0]);
+ const GVArray &virtual_array = this->get_single_input__single(input, resources);
+ virtual_array.get_single_to_uninitialized(span[0]);
return span;
}
@@ -848,10 +866,10 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__single(const MFInpu
}
}
- GVSpan virtual_span = this->get_single_input__single(input);
+ const GVArray &virtual_array = this->get_single_input__single(input, resources);
void *new_buffer = allocator_.allocate(type.size(), type.alignment());
- type.copy_to_uninitialized(virtual_span.as_single_element(), new_buffer);
+ virtual_array.get_single_to_uninitialized(new_buffer);
GMutableSpan new_array_ref(type, new_buffer, 1);
OwnSingleValue *new_value =
@@ -861,7 +879,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__single(const MFInpu
}
GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__full(const MFInputSocket &input,
- const MFOutputSocket &output)
+ const MFOutputSocket &output,
+ ResourceCollector &resources)
{
const MFOutputSocket &from = *input.origin();
const MFOutputSocket &to = output;
@@ -875,8 +894,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__full(const MFInput
if (to_any_value != nullptr) {
BLI_assert(to_any_value->type == ValueType::OutputVector);
GVectorArray &vector_array = *static_cast<OutputVectorValue *>(to_any_value)->vector_array;
- GVArraySpan virtual_array_span = this->get_vector_input__full(input);
- vector_array.extend(mask_, virtual_array_span);
+ const GVVectorArray &virtual_vector_array = this->get_vector_input__full(input, resources);
+ vector_array.extend(mask_, virtual_vector_array);
return vector_array;
}
@@ -890,10 +909,10 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__full(const MFInput
}
}
- GVArraySpan virtual_array_span = this->get_vector_input__full(input);
+ const GVVectorArray &virtual_vector_array = this->get_vector_input__full(input, resources);
GVectorArray *new_vector_array = new GVectorArray(base_type, min_array_size_);
- new_vector_array->extend(mask_, virtual_array_span);
+ new_vector_array->extend(mask_, virtual_vector_array);
OwnVectorValue *new_value =
allocator_.construct<OwnVectorValue>(*new_vector_array, to.targets().size()).release();
@@ -903,7 +922,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__full(const MFInput
}
GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__single(const MFInputSocket &input,
- const MFOutputSocket &output)
+ const MFOutputSocket &output,
+ ResourceCollector &resources)
{
const MFOutputSocket &from = *input.origin();
const MFOutputSocket &to = output;
@@ -918,8 +938,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__single(const MFInp
BLI_assert(to_any_value->type == ValueType::OutputVector);
GVectorArray &vector_array = *static_cast<OutputVectorValue *>(to_any_value)->vector_array;
BLI_assert(vector_array.size() == 1);
- GVArraySpan virtual_array_span = this->get_vector_input__single(input);
- vector_array.extend(0, virtual_array_span[0]);
+ const GVVectorArray &virtual_vector_array = this->get_vector_input__single(input, resources);
+ vector_array.extend({0}, virtual_vector_array);
return vector_array;
}
@@ -933,10 +953,10 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__single(const MFInp
}
}
- GVArraySpan virtual_array_span = this->get_vector_input__single(input);
+ const GVVectorArray &virtual_vector_array = this->get_vector_input__single(input, resources);
GVectorArray *new_vector_array = new GVectorArray(base_type, 1);
- new_vector_array->extend(0, virtual_array_span[0]);
+ new_vector_array->extend({0}, virtual_vector_array);
OwnVectorValue *new_value =
allocator_.construct<OwnVectorValue>(*new_vector_array, to.targets().size()).release();
@@ -944,7 +964,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__single(const MFInp
return *new_vector_array;
}
-GVSpan MFNetworkEvaluationStorage::get_single_input__full(const MFInputSocket &socket)
+const GVArray &MFNetworkEvaluationStorage::get_single_input__full(const MFInputSocket &socket,
+ ResourceCollector &resources)
{
const MFOutputSocket &origin = *socket.origin();
Value *any_value = value_per_output_id_[origin.id()];
@@ -953,26 +974,28 @@ GVSpan MFNetworkEvaluationStorage::get_single_input__full(const MFInputSocket &s
if (any_value->type == ValueType::OwnSingle) {
OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value);
if (value->is_single_allocated) {
- return GVSpan::FromSingle(value->span.type(), value->span.data(), min_array_size_);
+ return resources.construct<GVArrayForSingleValueRef>(
+ __func__, value->span.type(), min_array_size_, value->span.data());
}
- return value->span;
+ return resources.construct<GVArrayForGSpan>(__func__, value->span);
}
if (any_value->type == ValueType::InputSingle) {
InputSingleValue *value = static_cast<InputSingleValue *>(any_value);
- return value->virtual_span;
+ return value->virtual_array;
}
if (any_value->type == ValueType::OutputSingle) {
OutputSingleValue *value = static_cast<OutputSingleValue *>(any_value);
BLI_assert(value->is_computed);
- return value->span;
+ return resources.construct<GVArrayForGSpan>(__func__, value->span);
}
BLI_assert(false);
- return GVSpan(CPPType::get<float>());
+ return resources.construct<GVArrayForEmpty>(__func__, CPPType::get<float>());
}
-GVSpan MFNetworkEvaluationStorage::get_single_input__single(const MFInputSocket &socket)
+const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInputSocket &socket,
+ ResourceCollector &resources)
{
const MFOutputSocket &origin = *socket.origin();
Value *any_value = value_per_output_id_[origin.id()];
@@ -981,25 +1004,26 @@ GVSpan MFNetworkEvaluationStorage::get_single_input__single(const MFInputSocket
if (any_value->type == ValueType::OwnSingle) {
OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value);
BLI_assert(value->span.size() == 1);
- return value->span;
+ return resources.construct<GVArrayForGSpan>(__func__, value->span);
}
if (any_value->type == ValueType::InputSingle) {
InputSingleValue *value = static_cast<InputSingleValue *>(any_value);
- BLI_assert(value->virtual_span.is_single_element());
- return value->virtual_span;
+ BLI_assert(value->virtual_array.is_single());
+ return value->virtual_array;
}
if (any_value->type == ValueType::OutputSingle) {
OutputSingleValue *value = static_cast<OutputSingleValue *>(any_value);
BLI_assert(value->is_computed);
BLI_assert(value->span.size() == 1);
- return value->span;
+ return resources.construct<GVArrayForGSpan>(__func__, value->span);
}
BLI_assert(false);
- return GVSpan(CPPType::get<float>());
+ return resources.construct<GVArrayForEmpty>(__func__, CPPType::get<float>());
}
-GVArraySpan MFNetworkEvaluationStorage::get_vector_input__full(const MFInputSocket &socket)
+const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full(
+ const MFInputSocket &socket, ResourceCollector &resources)
{
const MFOutputSocket &origin = *socket.origin();
Value *any_value = value_per_output_id_[origin.id()];
@@ -1009,25 +1033,27 @@ GVArraySpan MFNetworkEvaluationStorage::get_vector_input__full(const MFInputSock
OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value);
if (value->vector_array->size() == 1) {
GSpan span = (*value->vector_array)[0];
- return GVArraySpan(span, min_array_size_);
+ return resources.construct<GVVectorArrayForSingleGSpan>(__func__, span, min_array_size_);
}
- return *value->vector_array;
+ return resources.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
}
if (any_value->type == ValueType::InputVector) {
InputVectorValue *value = static_cast<InputVectorValue *>(any_value);
- return value->virtual_array_span;
+ return value->virtual_vector_array;
}
if (any_value->type == ValueType::OutputVector) {
OutputVectorValue *value = static_cast<OutputVectorValue *>(any_value);
- return *value->vector_array;
+ return resources.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
}
BLI_assert(false);
- return GVArraySpan(CPPType::get<float>());
+ return resources.construct<GVVectorArrayForSingleGSpan>(
+ __func__, GSpan(CPPType::get<float>()), 0);
}
-GVArraySpan MFNetworkEvaluationStorage::get_vector_input__single(const MFInputSocket &socket)
+const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single(
+ const MFInputSocket &socket, ResourceCollector &resources)
{
const MFOutputSocket &origin = *socket.origin();
Value *any_value = value_per_output_id_[origin.id()];
@@ -1036,21 +1062,22 @@ GVArraySpan MFNetworkEvaluationStorage::get_vector_input__single(const MFInputSo
if (any_value->type == ValueType::OwnVector) {
OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value);
BLI_assert(value->vector_array->size() == 1);
- return *value->vector_array;
+ return resources.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
}
if (any_value->type == ValueType::InputVector) {
InputVectorValue *value = static_cast<InputVectorValue *>(any_value);
- BLI_assert(value->virtual_array_span.is_single_array());
- return value->virtual_array_span;
+ BLI_assert(value->virtual_vector_array.is_single_vector());
+ return value->virtual_vector_array;
}
if (any_value->type == ValueType::OutputVector) {
OutputVectorValue *value = static_cast<OutputVectorValue *>(any_value);
BLI_assert(value->vector_array->size() == 1);
- return *value->vector_array;
+ return resources.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
}
BLI_assert(false);
- return GVArraySpan(CPPType::get<float>());
+ return resources.construct<GVVectorArrayForSingleGSpan>(
+ __func__, GSpan(CPPType::get<float>()), 0);
}
/** \} */
diff --git a/source/blender/functions/tests/FN_array_spans_test.cc b/source/blender/functions/tests/FN_array_spans_test.cc
deleted file mode 100644
index af2bc0aad91..00000000000
--- a/source/blender/functions/tests/FN_array_spans_test.cc
+++ /dev/null
@@ -1,134 +0,0 @@
-/* Apache License, Version 2.0 */
-
-#include "testing/testing.h"
-
-#include "FN_array_spans.hh"
-#include "FN_generic_vector_array.hh"
-
-#include "BLI_array.hh"
-
-namespace blender::fn::tests {
-
-TEST(virtual_array_span, EmptyConstructor)
-{
- VArraySpan<int> span;
- EXPECT_EQ(span.size(), 0);
- EXPECT_TRUE(span.is_empty());
-
- GVArraySpan converted(span);
- EXPECT_EQ(converted.type(), CPPType::get<int>());
- EXPECT_EQ(converted.size(), 0);
-}
-
-TEST(virtual_array_span, SingleArrayConstructor)
-{
- std::array<int, 4> values = {3, 4, 5, 6};
- VArraySpan<int> span{Span<int>(values), 3};
- EXPECT_EQ(span.size(), 3);
- EXPECT_FALSE(span.is_empty());
- EXPECT_EQ(span[0].size(), 4);
- EXPECT_EQ(span[1].size(), 4);
- EXPECT_EQ(span[2].size(), 4);
- EXPECT_EQ(span[0][0], 3);
- EXPECT_EQ(span[0][1], 4);
- EXPECT_EQ(span[0][2], 5);
- EXPECT_EQ(span[0][3], 6);
- EXPECT_EQ(span[1][3], 6);
- EXPECT_EQ(span[2][1], 4);
-
- GVArraySpan converted(span);
- EXPECT_EQ(converted.type(), CPPType::get<int>());
- EXPECT_EQ(converted.size(), 3);
- EXPECT_EQ(converted[0].size(), 4);
- EXPECT_EQ(converted[1].size(), 4);
- EXPECT_EQ(converted[1][2], &values[2]);
-}
-
-TEST(virtual_array_span, MultipleArrayConstructor)
-{
- std::array<int, 4> values0 = {1, 2, 3, 4};
- std::array<int, 2> values1 = {6, 7};
- std::array<int, 1> values2 = {8};
- std::array<const int *, 3> starts = {values0.data(), values1.data(), values2.data()};
- std::array<int64_t, 3> sizes{static_cast<int64_t>(values0.size()),
- static_cast<int64_t>(values1.size()),
- static_cast<int64_t>(values2.size())};
-
- VArraySpan<int> span{starts, sizes};
- EXPECT_EQ(span.size(), 3);
- EXPECT_FALSE(span.is_empty());
- EXPECT_EQ(span[0].size(), 4);
- EXPECT_EQ(span[1].size(), 2);
- EXPECT_EQ(span[2].size(), 1);
- EXPECT_EQ(&span[0][0], values0.data());
- EXPECT_EQ(&span[1][0], values1.data());
- EXPECT_EQ(&span[2][0], values2.data());
- EXPECT_EQ(span[2][0], 8);
- EXPECT_EQ(span[1][1], 7);
-
- GVArraySpan converted(span);
- EXPECT_EQ(converted.type(), CPPType::get<int>());
- EXPECT_EQ(converted.size(), 3);
- EXPECT_EQ(converted[0].size(), 4);
- EXPECT_EQ(converted[1].size(), 2);
- EXPECT_EQ(converted[2].size(), 1);
- EXPECT_EQ(converted[0][0], values0.data());
- EXPECT_EQ(converted[1][1], values1.data() + 1);
-}
-
-TEST(generic_virtual_array_span, TypeConstructor)
-{
- GVArraySpan span{CPPType::get<int32_t>()};
- EXPECT_EQ(span.size(), 0);
- EXPECT_TRUE(span.is_empty());
-
- VArraySpan converted = span.typed<int>();
- EXPECT_EQ(converted.size(), 0);
-}
-
-TEST(generic_virtual_array_span, GSpanConstructor)
-{
- std::array<std::string, 3> values = {"hello", "world", "test"};
- GVArraySpan span{GSpan(CPPType::get<std::string>(), values.data(), 3), 5};
- EXPECT_EQ(span.size(), 5);
- EXPECT_FALSE(span.is_empty());
- EXPECT_EQ(span[0][0], values.data());
- EXPECT_EQ(span[1][0], values.data());
- EXPECT_EQ(span[4][0], values.data());
- EXPECT_EQ(span[0].size(), 3);
- EXPECT_EQ(span[2].size(), 3);
- EXPECT_EQ(*(std::string *)span[3][1], "world");
-
- VArraySpan converted = span.typed<std::string>();
- EXPECT_EQ(converted.size(), 5);
- EXPECT_EQ(converted[0][0], "hello");
- EXPECT_EQ(converted[1][0], "hello");
- EXPECT_EQ(converted[4][0], "hello");
- EXPECT_EQ(converted[0].size(), 3);
- EXPECT_EQ(converted[2].size(), 3);
-}
-
-TEST(generic_virtual_array_span, IsSingleArray1)
-{
- Array<int> values = {5, 6, 7};
- GVArraySpan span{GSpan(values.as_span()), 4};
- EXPECT_TRUE(span.is_single_array());
-
- VArraySpan converted = span.typed<int>();
- EXPECT_TRUE(converted.is_single_array());
-}
-
-TEST(generic_virtual_array_span, IsSingleArray2)
-{
- GVectorArray vectors{CPPType::get<int32_t>(), 3};
- GVectorArrayRef<int> vectors_ref = vectors;
- vectors_ref.append(1, 4);
-
- GVArraySpan span = vectors;
- EXPECT_FALSE(span.is_single_array());
-
- VArraySpan converted = span.typed<int>();
- EXPECT_FALSE(converted.is_single_array());
-}
-
-} // namespace blender::fn::tests
diff --git a/source/blender/functions/tests/FN_generic_span_test.cc b/source/blender/functions/tests/FN_generic_span_test.cc
new file mode 100644
index 00000000000..81057ee9c4f
--- /dev/null
+++ b/source/blender/functions/tests/FN_generic_span_test.cc
@@ -0,0 +1,53 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "FN_generic_span.hh"
+
+namespace blender::fn::tests {
+
+TEST(generic_span, TypeConstructor)
+{
+ GSpan span(CPPType::get<float>());
+ EXPECT_EQ(span.size(), 0);
+ EXPECT_EQ(span.typed<float>().size(), 0);
+ EXPECT_TRUE(span.is_empty());
+}
+
+TEST(generic_span, BufferAndSizeConstructor)
+{
+ int values[4] = {6, 7, 3, 2};
+ void *buffer = (void *)values;
+ GSpan span(CPPType::get<int32_t>(), buffer, 4);
+ EXPECT_EQ(span.size(), 4);
+ EXPECT_FALSE(span.is_empty());
+ EXPECT_EQ(span.typed<int>().size(), 4);
+ EXPECT_EQ(span[0], &values[0]);
+ EXPECT_EQ(span[1], &values[1]);
+ EXPECT_EQ(span[2], &values[2]);
+ EXPECT_EQ(span[3], &values[3]);
+}
+
+TEST(generic_mutable_span, TypeConstructor)
+{
+ GMutableSpan span(CPPType::get<int32_t>());
+ EXPECT_EQ(span.size(), 0);
+ EXPECT_TRUE(span.is_empty());
+}
+
+TEST(generic_mutable_span, BufferAndSizeConstructor)
+{
+ int values[4] = {4, 7, 3, 5};
+ void *buffer = (void *)values;
+ GMutableSpan span(CPPType::get<int32_t>(), buffer, 4);
+ EXPECT_EQ(span.size(), 4);
+ EXPECT_FALSE(span.is_empty());
+ EXPECT_EQ(span.typed<int>().size(), 4);
+ EXPECT_EQ(values[2], 3);
+ *(int *)span[2] = 10;
+ EXPECT_EQ(values[2], 10);
+ span.typed<int>()[2] = 20;
+ EXPECT_EQ(values[2], 20);
+}
+
+} // namespace blender::fn::tests
diff --git a/source/blender/functions/tests/FN_generic_vector_array_test.cc b/source/blender/functions/tests/FN_generic_vector_array_test.cc
index 77ec05f12dc..3e78aef4841 100644
--- a/source/blender/functions/tests/FN_generic_vector_array_test.cc
+++ b/source/blender/functions/tests/FN_generic_vector_array_test.cc
@@ -1,101 +1,43 @@
/* Apache License, Version 2.0 */
-#include "FN_generic_vector_array.hh"
-
#include "testing/testing.h"
+#include "FN_generic_vector_array.hh"
+
namespace blender::fn::tests {
-TEST(generic_vector_array, Constructor)
+TEST(generic_vector_array, Construct)
{
- GVectorArray vectors{CPPType::get<int32_t>(), 3};
- EXPECT_EQ(vectors.size(), 3);
- EXPECT_EQ(vectors.lengths().size(), 3);
- EXPECT_EQ(vectors.starts().size(), 3);
- EXPECT_EQ(vectors.lengths()[0], 0);
- EXPECT_EQ(vectors.lengths()[1], 0);
- EXPECT_EQ(vectors.lengths()[2], 0);
- EXPECT_EQ(vectors.type(), CPPType::get<int32_t>());
+ GVectorArray vector_array{CPPType::get<int>(), 4};
+ EXPECT_EQ(vector_array.size(), 4);
+ EXPECT_FALSE(vector_array.is_empty());
}
TEST(generic_vector_array, Append)
{
- GVectorArray vectors{CPPType::get<std::string>(), 3};
- std::string value = "hello";
- vectors.append(0, &value);
- value = "world";
- vectors.append(0, &value);
- vectors.append(2, &value);
-
- EXPECT_EQ(vectors.lengths()[0], 2);
- EXPECT_EQ(vectors.lengths()[1], 0);
- EXPECT_EQ(vectors.lengths()[2], 1);
- EXPECT_EQ(vectors[0].size(), 2);
- EXPECT_EQ(vectors[0].typed<std::string>()[0], "hello");
- EXPECT_EQ(vectors[0].typed<std::string>()[1], "world");
- EXPECT_EQ(vectors[2].typed<std::string>()[0], "world");
-}
-
-TEST(generic_vector_array, AsArraySpan)
-{
- GVectorArray vectors{CPPType::get<int32_t>(), 3};
- int value = 3;
- vectors.append(0, &value);
- vectors.append(0, &value);
- value = 5;
- vectors.append(2, &value);
- vectors.append(2, &value);
- vectors.append(2, &value);
-
- GVArraySpan span = vectors;
- EXPECT_EQ(span.type(), CPPType::get<int32_t>());
- EXPECT_EQ(span.size(), 3);
- EXPECT_EQ(span[0].size(), 2);
- EXPECT_EQ(span[1].size(), 0);
- EXPECT_EQ(span[2].size(), 3);
- EXPECT_EQ(span[0].typed<int>()[1], 3);
- EXPECT_EQ(span[2].typed<int>()[0], 5);
-}
-
-TEST(generic_vector_array, TypedRef)
-{
- GVectorArray vectors{CPPType::get<int32_t>(), 4};
- GVectorArrayRef<int> ref = vectors.typed<int>();
- ref.append(0, 2);
- ref.append(0, 6);
- ref.append(0, 7);
- ref.append(2, 1);
- ref.append(2, 1);
- ref.append(3, 5);
- ref.append(3, 6);
-
- EXPECT_EQ(ref[0].size(), 3);
- EXPECT_EQ(vectors[0].size(), 3);
- EXPECT_EQ(ref[0][0], 2);
- EXPECT_EQ(ref[0][1], 6);
- EXPECT_EQ(ref[0][2], 7);
- EXPECT_EQ(ref[1].size(), 0);
- EXPECT_EQ(ref[2][0], 1);
- EXPECT_EQ(ref[2][1], 1);
- EXPECT_EQ(ref[3][0], 5);
- EXPECT_EQ(ref[3][1], 6);
+ GVectorArray vector_array{CPPType::get<int>(), 3};
+ int value1 = 2;
+ vector_array.append(1, &value1);
+ vector_array.append(1, &value1);
+ int value2 = 3;
+ vector_array.append(0, &value2);
+ vector_array.append(1, &value2);
+
+ EXPECT_EQ(vector_array[0].size(), 1);
+ EXPECT_EQ(vector_array[1].size(), 3);
+ EXPECT_EQ(vector_array[2].size(), 0);
}
TEST(generic_vector_array, Extend)
{
- GVectorArray vectors{CPPType::get<int32_t>(), 3};
- GVectorArrayRef<int> ref = vectors;
-
- ref.extend(1, {5, 6, 7});
- ref.extend(0, {3});
-
- EXPECT_EQ(vectors[0].size(), 1);
- EXPECT_EQ(vectors[1].size(), 3);
- EXPECT_EQ(vectors[2].size(), 0);
- EXPECT_EQ(ref[1][0], 5);
- EXPECT_EQ(ref[1][1], 6);
- EXPECT_EQ(ref[1][2], 7);
- EXPECT_EQ(ref[0][0], 3);
+ GVectorArray vector_array{CPPType::get<int>(), 3};
+ vector_array.extend(0, Span<int>({1, 4, 6, 4}));
+ vector_array.extend(1, Span<int>());
+ vector_array.extend(0, Span<int>({10, 20, 30}));
+
+ EXPECT_EQ(vector_array[0].size(), 7);
+ EXPECT_EQ(vector_array[1].size(), 0);
+ EXPECT_EQ(vector_array[2].size(), 0);
}
} // namespace blender::fn::tests
diff --git a/source/blender/functions/tests/FN_multi_function_network_test.cc b/source/blender/functions/tests/FN_multi_function_network_test.cc
index f226e0eac2e..70da0315b93 100644
--- a/source/blender/functions/tests/FN_multi_function_network_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_network_test.cc
@@ -76,12 +76,9 @@ class ConcatVectorsFunction : public MultiFunction {
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
{
- GVectorArrayRef<int> a = params.vector_mutable<int>(0);
- VArraySpan<int> b = params.readonly_vector_input<int>(1);
-
- for (int64_t i : mask) {
- a.extend(i, b[i]);
- }
+ GVectorArray &a = params.vector_mutable(0);
+ const GVVectorArray &b = params.readonly_vector_input(1);
+ a.extend(mask, b);
}
};
@@ -96,8 +93,8 @@ class AppendFunction : public MultiFunction {
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
{
- GVectorArrayRef<int> vectors = params.vector_mutable<int>(0);
- VSpan<int> values = params.readonly_single_input<int>(1);
+ GVectorArray_TypedMutableRef<int> vectors = params.vector_mutable<int>(0);
+ const VArray<int> &values = params.readonly_single_input<int>(1);
for (int64_t i : mask) {
vectors.append(i, values[i]);
@@ -116,14 +113,13 @@ class SumVectorFunction : public MultiFunction {
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
{
- VArraySpan<int> vectors = params.readonly_vector_input<int>(0);
+ const VVectorArray<int> &vectors = params.readonly_vector_input<int>(0);
MutableSpan<int> sums = params.uninitialized_single_output<int>(1);
for (int64_t i : mask) {
int sum = 0;
- VSpan<int> vector = vectors[i];
- for (int j = 0; j < vector.size(); j++) {
- sum += vector[j];
+ for (int j : IndexRange(vectors.get_vector_size(i))) {
+ sum += vectors.get_vector_element(i, j);
}
sums[i] = sum;
}
@@ -141,8 +137,8 @@ class CreateRangeFunction : public MultiFunction {
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
{
- VSpan<int> sizes = params.readonly_single_input<int>(0, "Size");
- GVectorArrayRef<int> ranges = params.vector_output<int>(1, "Range");
+ const VArray<int> &sizes = params.readonly_single_input<int>(0, "Size");
+ GVectorArray_TypedMutableRef<int> ranges = params.vector_output<int>(1, "Range");
for (int64_t i : mask) {
int size = sizes[i];
@@ -199,7 +195,8 @@ TEST(multi_function_network, Test2)
Array<int> output_value_2(5, -1);
MFParamsBuilder params(network_fn, 5);
- params.add_readonly_vector_input(GVArraySpan(input_value_1.as_span(), 5));
+ GVVectorArrayForSingleGSpan inputs_1{input_value_1.as_span(), 5};
+ params.add_readonly_vector_input(inputs_1);
params.add_readonly_single_input(&input_value_2);
params.add_vector_output(output_value_1);
params.add_uninitialized_single_output(output_value_2.as_mutable_span());
@@ -222,9 +219,9 @@ TEST(multi_function_network, Test2)
}
{
GVectorArray input_value_1(CPPType::get<int32_t>(), 3);
- GVectorArrayRef<int> input_value_ref_1 = input_value_1;
- input_value_ref_1.extend(0, {3, 4, 5});
- input_value_ref_1.extend(1, {1, 2});
+ GVectorArray_TypedMutableRef<int> input_value_1_ref{input_value_1};
+ input_value_1_ref.extend(0, {3, 4, 5});
+ input_value_1_ref.extend(1, {1, 2});
Array<int> input_value_2 = {4, 2, 3};
diff --git a/source/blender/functions/tests/FN_multi_function_test.cc b/source/blender/functions/tests/FN_multi_function_test.cc
index cc023bce597..3ed60665149 100644
--- a/source/blender/functions/tests/FN_multi_function_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_test.cc
@@ -20,8 +20,8 @@ class AddFunction : public MultiFunction {
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
{
- VSpan<int> a = params.readonly_single_input<int>(0, "A");
- VSpan<int> b = params.readonly_single_input<int>(1, "B");
+ const VArray<int> &a = params.readonly_single_input<int>(0, "A");
+ const VArray<int> &b = params.readonly_single_input<int>(1, "B");
MutableSpan<int> result = params.uninitialized_single_output<int>(2, "Result");
for (int64_t i : mask) {
@@ -63,7 +63,7 @@ class AddPrefixFunction : public MultiFunction {
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
{
- VSpan<std::string> prefixes = params.readonly_single_input<std::string>(0, "Prefix");
+ const VArray<std::string> &prefixes = params.readonly_single_input<std::string>(0, "Prefix");
MutableSpan<std::string> strings = params.single_mutable<std::string>(1, "Strings");
for (int64_t i : mask) {
@@ -110,13 +110,13 @@ class CreateRangeFunction : public MultiFunction {
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
{
- VSpan<uint> sizes = params.readonly_single_input<uint>(0, "Size");
- GVectorArrayRef<uint> ranges = params.vector_output<uint>(1, "Range");
+ const VArray<uint> &sizes = params.readonly_single_input<uint>(0, "Size");
+ GVectorArray &ranges = params.vector_output(1, "Range");
for (int64_t i : mask) {
uint size = sizes[i];
for (uint j : IndexRange(size)) {
- ranges.append(i, j);
+ ranges.append(i, &j);
}
}
}
@@ -127,7 +127,7 @@ TEST(multi_function, CreateRangeFunction)
CreateRangeFunction fn;
GVectorArray ranges(CPPType::get<uint>(), 5);
- GVectorArrayRef<uint> ranges_ref(ranges);
+ GVectorArray_TypedMutableRef<uint> ranges_ref{ranges};
Array<uint> sizes = {3, 0, 6, 1, 4};
MFParamsBuilder params(fn, ranges.size());
@@ -138,11 +138,11 @@ TEST(multi_function, CreateRangeFunction)
fn.call({0, 1, 2, 3}, params, context);
- EXPECT_EQ(ranges_ref[0].size(), 3);
- EXPECT_EQ(ranges_ref[1].size(), 0);
- EXPECT_EQ(ranges_ref[2].size(), 6);
- EXPECT_EQ(ranges_ref[3].size(), 1);
- EXPECT_EQ(ranges_ref[4].size(), 0);
+ EXPECT_EQ(ranges[0].size(), 3);
+ EXPECT_EQ(ranges[1].size(), 0);
+ EXPECT_EQ(ranges[2].size(), 6);
+ EXPECT_EQ(ranges[3].size(), 1);
+ EXPECT_EQ(ranges[4].size(), 0);
EXPECT_EQ(ranges_ref[0][0], 0);
EXPECT_EQ(ranges_ref[0][1], 1);
@@ -163,10 +163,13 @@ class GenericAppendFunction : public MultiFunction {
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
{
GVectorArray &vectors = params.vector_mutable(0, "Vector");
- GVSpan values = params.readonly_single_input(1, "Value");
+ const GVArray &values = params.readonly_single_input(1, "Value");
for (int64_t i : mask) {
- vectors.append(i, values[i]);
+ BUFFER_FOR_CPP_TYPE_VALUE(values.type(), buffer);
+ values.get(i, buffer);
+ vectors.append(i, buffer);
+ values.type().destruct(buffer);
}
}
};
@@ -176,7 +179,7 @@ TEST(multi_function, GenericAppendFunction)
GenericAppendFunction fn(CPPType::get<int32_t>());
GVectorArray vectors(CPPType::get<int32_t>(), 4);
- GVectorArrayRef<int> vectors_ref(vectors);
+ GVectorArray_TypedMutableRef<int> vectors_ref{vectors};
vectors_ref.append(0, 1);
vectors_ref.append(0, 2);
vectors_ref.append(2, 6);
@@ -190,10 +193,10 @@ TEST(multi_function, GenericAppendFunction)
fn.call(IndexRange(vectors.size()), params, context);
- EXPECT_EQ(vectors_ref[0].size(), 3);
- EXPECT_EQ(vectors_ref[1].size(), 1);
- EXPECT_EQ(vectors_ref[2].size(), 2);
- EXPECT_EQ(vectors_ref[3].size(), 1);
+ EXPECT_EQ(vectors[0].size(), 3);
+ EXPECT_EQ(vectors[1].size(), 1);
+ EXPECT_EQ(vectors[2].size(), 2);
+ EXPECT_EQ(vectors[3].size(), 1);
EXPECT_EQ(vectors_ref[0][0], 1);
EXPECT_EQ(vectors_ref[0][1], 2);
@@ -342,11 +345,11 @@ TEST(multi_function, CustomMF_GenericConstantArray)
CustomMF_GenericConstantArray fn{GSpan(Span(values))};
EXPECT_EQ(fn.param_name(0), "[3, 4, 5, 6, ]");
- GVectorArray g_vector_array{CPPType::get<int32_t>(), 4};
- GVectorArrayRef<int> vector_array = g_vector_array;
+ GVectorArray vector_array{CPPType::get<int32_t>(), 4};
+ GVectorArray_TypedMutableRef<int> vector_array_ref{vector_array};
- MFParamsBuilder params(fn, g_vector_array.size());
- params.add_vector_output(g_vector_array);
+ MFParamsBuilder params(fn, vector_array.size());
+ params.add_vector_output(vector_array);
MFContextBuilder context;
@@ -357,10 +360,10 @@ TEST(multi_function, CustomMF_GenericConstantArray)
EXPECT_EQ(vector_array[2].size(), 4);
EXPECT_EQ(vector_array[3].size(), 4);
for (int i = 1; i < 4; i++) {
- EXPECT_EQ(vector_array[i][0], 3);
- EXPECT_EQ(vector_array[i][1], 4);
- EXPECT_EQ(vector_array[i][2], 5);
- EXPECT_EQ(vector_array[i][3], 6);
+ EXPECT_EQ(vector_array_ref[i][0], 3);
+ EXPECT_EQ(vector_array_ref[i][1], 4);
+ EXPECT_EQ(vector_array_ref[i][2], 5);
+ EXPECT_EQ(vector_array_ref[i][3], 6);
}
}
diff --git a/source/blender/functions/tests/FN_spans_test.cc b/source/blender/functions/tests/FN_spans_test.cc
deleted file mode 100644
index fbcf1fda71e..00000000000
--- a/source/blender/functions/tests/FN_spans_test.cc
+++ /dev/null
@@ -1,222 +0,0 @@
-/* Apache License, Version 2.0 */
-
-#include "testing/testing.h"
-
-#include "FN_spans.hh"
-
-namespace blender::fn::tests {
-
-TEST(generic_span, TypeConstructor)
-{
- GSpan span(CPPType::get<float>());
- EXPECT_EQ(span.size(), 0);
- EXPECT_EQ(span.typed<float>().size(), 0);
- EXPECT_TRUE(span.is_empty());
-}
-
-TEST(generic_span, BufferAndSizeConstructor)
-{
- int values[4] = {6, 7, 3, 2};
- void *buffer = (void *)values;
- GSpan span(CPPType::get<int32_t>(), buffer, 4);
- EXPECT_EQ(span.size(), 4);
- EXPECT_FALSE(span.is_empty());
- EXPECT_EQ(span.typed<int>().size(), 4);
- EXPECT_EQ(span[0], &values[0]);
- EXPECT_EQ(span[1], &values[1]);
- EXPECT_EQ(span[2], &values[2]);
- EXPECT_EQ(span[3], &values[3]);
-}
-
-TEST(generic_mutable_span, TypeConstructor)
-{
- GMutableSpan span(CPPType::get<int32_t>());
- EXPECT_EQ(span.size(), 0);
- EXPECT_TRUE(span.is_empty());
-}
-
-TEST(generic_mutable_span, BufferAndSizeConstructor)
-{
- int values[4] = {4, 7, 3, 5};
- void *buffer = (void *)values;
- GMutableSpan span(CPPType::get<int32_t>(), buffer, 4);
- EXPECT_EQ(span.size(), 4);
- EXPECT_FALSE(span.is_empty());
- EXPECT_EQ(span.typed<int>().size(), 4);
- EXPECT_EQ(values[2], 3);
- *(int *)span[2] = 10;
- EXPECT_EQ(values[2], 10);
- span.typed<int>()[2] = 20;
- EXPECT_EQ(values[2], 20);
-}
-
-TEST(virtual_span, EmptyConstructor)
-{
- VSpan<int> span;
- EXPECT_EQ(span.size(), 0);
- EXPECT_TRUE(span.is_empty());
- EXPECT_FALSE(span.is_single_element());
- EXPECT_TRUE(span.is_full_array());
-
- GVSpan converted(span);
- EXPECT_EQ(converted.type(), CPPType::get<int>());
- EXPECT_EQ(converted.size(), 0);
-}
-
-TEST(virtual_span, SpanConstructor)
-{
- std::array<int, 5> values = {7, 3, 8, 6, 4};
- Span<int> span = values;
- VSpan<int> virtual_span = span;
- EXPECT_EQ(virtual_span.size(), 5);
- EXPECT_FALSE(virtual_span.is_empty());
- EXPECT_EQ(virtual_span[0], 7);
- EXPECT_EQ(virtual_span[2], 8);
- EXPECT_EQ(virtual_span[3], 6);
- EXPECT_FALSE(virtual_span.is_single_element());
- EXPECT_TRUE(virtual_span.is_full_array());
-
- GVSpan converted(span);
- EXPECT_EQ(converted.type(), CPPType::get<int>());
- EXPECT_EQ(converted.size(), 5);
-}
-
-TEST(virtual_span, PointerSpanConstructor)
-{
- int x0 = 3;
- int x1 = 6;
- int x2 = 7;
- std::array<const int *, 3> pointers = {&x0, &x2, &x1};
- VSpan<int> span = Span<const int *>(pointers);
- EXPECT_EQ(span.size(), 3);
- EXPECT_FALSE(span.is_empty());
- EXPECT_EQ(span[0], 3);
- EXPECT_EQ(span[1], 7);
- EXPECT_EQ(span[2], 6);
- EXPECT_EQ(&span[1], &x2);
- EXPECT_FALSE(span.is_single_element());
- EXPECT_FALSE(span.is_full_array());
-
- GVSpan converted(span);
- EXPECT_EQ(converted.type(), CPPType::get<int>());
- EXPECT_EQ(converted.size(), 3);
- EXPECT_EQ(converted[0], &x0);
- EXPECT_EQ(converted[1], &x2);
- EXPECT_EQ(converted[2], &x1);
-}
-
-TEST(virtual_span, SingleConstructor)
-{
- int value = 5;
- VSpan<int> span = VSpan<int>::FromSingle(&value, 3);
- EXPECT_EQ(span.size(), 3);
- EXPECT_FALSE(span.is_empty());
- EXPECT_EQ(span[0], 5);
- EXPECT_EQ(span[1], 5);
- EXPECT_EQ(span[2], 5);
- EXPECT_EQ(&span[0], &value);
- EXPECT_EQ(&span[1], &value);
- EXPECT_EQ(&span[2], &value);
- EXPECT_TRUE(span.is_single_element());
- EXPECT_FALSE(span.is_full_array());
-
- GVSpan converted(span);
- EXPECT_EQ(converted.type(), CPPType::get<int>());
- EXPECT_EQ(converted.size(), 3);
- EXPECT_EQ(converted[0], &value);
- EXPECT_EQ(converted[1], &value);
- EXPECT_EQ(converted[2], &value);
-}
-
-TEST(generic_virtual_span, TypeConstructor)
-{
- GVSpan span(CPPType::get<int32_t>());
- EXPECT_EQ(span.size(), 0);
- EXPECT_TRUE(span.is_empty());
- EXPECT_FALSE(span.is_single_element());
- EXPECT_TRUE(span.is_full_array());
-
- VSpan<int> converted = span.typed<int>();
- EXPECT_EQ(converted.size(), 0);
-}
-
-TEST(generic_virtual_span, GenericSpanConstructor)
-{
- int values[4] = {3, 4, 5, 6};
- GVSpan span{GSpan(CPPType::get<int32_t>(), values, 4)};
- EXPECT_EQ(span.size(), 4);
- EXPECT_FALSE(span.is_empty());
- EXPECT_EQ(span[0], &values[0]);
- EXPECT_EQ(span[1], &values[1]);
- EXPECT_EQ(span[2], &values[2]);
- EXPECT_EQ(span[3], &values[3]);
- EXPECT_FALSE(span.is_single_element());
- EXPECT_TRUE(span.is_full_array());
-
- int materialized[4] = {0};
- span.materialize_to_uninitialized(materialized);
- EXPECT_EQ(materialized[0], 3);
- EXPECT_EQ(materialized[1], 4);
- EXPECT_EQ(materialized[2], 5);
- EXPECT_EQ(materialized[3], 6);
-
- VSpan<int> converted = span.typed<int>();
- EXPECT_EQ(converted.size(), 4);
- EXPECT_EQ(converted[0], 3);
- EXPECT_EQ(converted[1], 4);
- EXPECT_EQ(converted[2], 5);
- EXPECT_EQ(converted[3], 6);
-}
-
-TEST(generic_virtual_span, SpanConstructor)
-{
- std::array<int, 3> values = {6, 7, 8};
- GVSpan span{Span<int>(values)};
- EXPECT_EQ(span.type(), CPPType::get<int32_t>());
- EXPECT_EQ(span.size(), 3);
- EXPECT_EQ(span[0], &values[0]);
- EXPECT_EQ(span[1], &values[1]);
- EXPECT_EQ(span[2], &values[2]);
- EXPECT_FALSE(span.is_single_element());
- EXPECT_TRUE(span.is_full_array());
-
- int materialized[3] = {0};
- span.materialize_to_uninitialized(materialized);
- EXPECT_EQ(materialized[0], 6);
- EXPECT_EQ(materialized[1], 7);
- EXPECT_EQ(materialized[2], 8);
-
- VSpan<int> converted = span.typed<int>();
- EXPECT_EQ(converted.size(), 3);
- EXPECT_EQ(converted[0], 6);
- EXPECT_EQ(converted[1], 7);
- EXPECT_EQ(converted[2], 8);
-}
-
-TEST(generic_virtual_span, SingleConstructor)
-{
- int value = 5;
- GVSpan span = GVSpan::FromSingle(CPPType::get<int32_t>(), &value, 3);
- EXPECT_EQ(span.size(), 3);
- EXPECT_FALSE(span.is_empty());
- EXPECT_EQ(span[0], &value);
- EXPECT_EQ(span[1], &value);
- EXPECT_EQ(span[2], &value);
- EXPECT_TRUE(span.is_single_element());
- EXPECT_EQ(span.as_single_element(), &value);
- EXPECT_FALSE(span.is_full_array());
-
- int materialized[3] = {0};
- span.materialize_to_uninitialized({1, 2}, materialized);
- EXPECT_EQ(materialized[0], 0);
- EXPECT_EQ(materialized[1], 5);
- EXPECT_EQ(materialized[2], 5);
-
- VSpan<int> converted = span.typed<int>();
- EXPECT_EQ(converted.size(), 3);
- EXPECT_EQ(converted[0], 5);
- EXPECT_EQ(converted[1], 5);
- EXPECT_EQ(converted[2], 5);
-}
-
-} // namespace blender::fn::tests
diff --git a/source/blender/nodes/function/nodes/node_fn_object_transforms.cc b/source/blender/nodes/function/nodes/node_fn_object_transforms.cc
index 26b25406590..55f592d7879 100644
--- a/source/blender/nodes/function/nodes/node_fn_object_transforms.cc
+++ b/source/blender/nodes/function/nodes/node_fn_object_transforms.cc
@@ -42,7 +42,7 @@ class ObjectTransformsFunction : public blender::fn::MultiFunction {
blender::fn::MFParams params,
blender::fn::MFContext context) const override
{
- blender::fn::VSpan handles =
+ const blender::VArray<blender::bke::PersistentObjectHandle> &handles =
params.readonly_single_input<blender::bke::PersistentObjectHandle>(0, "Object");
blender::MutableSpan locations = params.uninitialized_single_output<blender::float3>(
1, "Location");
diff --git a/source/blender/nodes/function/nodes/node_fn_random_float.cc b/source/blender/nodes/function/nodes/node_fn_random_float.cc
index d0ecb5592da..84ded73c601 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_float.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_float.cc
@@ -48,9 +48,9 @@ class RandomFloatFunction : public blender::fn::MultiFunction {
blender::fn::MFParams params,
blender::fn::MFContext UNUSED(context)) const override
{
- blender::fn::VSpan<float> min_values = params.readonly_single_input<float>(0, "Min");
- blender::fn::VSpan<float> max_values = params.readonly_single_input<float>(1, "Max");
- blender::fn::VSpan<int> seeds = params.readonly_single_input<int>(2, "Seed");
+ const blender::VArray<float> &min_values = params.readonly_single_input<float>(0, "Min");
+ const blender::VArray<float> &max_values = params.readonly_single_input<float>(1, "Max");
+ const blender::VArray<int> &seeds = params.readonly_single_input<int>(2, "Seed");
blender::MutableSpan<float> values = params.uninitialized_single_output<float>(3, "Value");
for (int64_t i : mask) {
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
index c01e390c513..3aa533599cf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
@@ -108,11 +108,11 @@ class MapRangeFunction : public blender::fn::MultiFunction {
blender::fn::MFParams params,
blender::fn::MFContext UNUSED(context)) const override
{
- blender::fn::VSpan<float> values = params.readonly_single_input<float>(0, "Value");
- blender::fn::VSpan<float> from_min = params.readonly_single_input<float>(1, "From Min");
- blender::fn::VSpan<float> from_max = params.readonly_single_input<float>(2, "From Max");
- blender::fn::VSpan<float> to_min = params.readonly_single_input<float>(3, "To Min");
- blender::fn::VSpan<float> to_max = params.readonly_single_input<float>(4, "To Max");
+ const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
+ const blender::VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
+ const blender::VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
+ const blender::VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
+ const blender::VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
blender::MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result");
for (int64_t i : mask) {
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
index 59b89c46fc7..a9057428981 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
@@ -74,8 +74,8 @@ class SeparateRGBFunction : public blender::fn::MultiFunction {
blender::fn::MFParams params,
blender::fn::MFContext UNUSED(context)) const override
{
- blender::fn::VSpan<blender::Color4f> colors = params.readonly_single_input<blender::Color4f>(
- 0, "Color");
+ const blender::VArray<blender::Color4f> &colors =
+ params.readonly_single_input<blender::Color4f>(0, "Color");
blender::MutableSpan<float> rs = params.uninitialized_single_output<float>(1, "R");
blender::MutableSpan<float> gs = params.uninitialized_single_output<float>(2, "G");
blender::MutableSpan<float> bs = params.uninitialized_single_output<float>(3, "B");
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
index 8b23327460f..c0dc66b3342 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
@@ -59,8 +59,8 @@ class MF_SeparateXYZ : public blender::fn::MultiFunction {
blender::fn::MFParams params,
blender::fn::MFContext UNUSED(context)) const override
{
- blender::fn::VSpan<blender::float3> vectors = params.readonly_single_input<blender::float3>(
- 0, "XYZ");
+ const blender::VArray<blender::float3> &vectors =
+ params.readonly_single_input<blender::float3>(0, "XYZ");
blender::MutableSpan<float> xs = params.uninitialized_single_output<float>(1, "X");
blender::MutableSpan<float> ys = params.uninitialized_single_output<float>(2, "Y");
blender::MutableSpan<float> zs = params.uninitialized_single_output<float>(3, "Z");
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
index a86a8bb8935..0d50582e23a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
@@ -142,7 +142,7 @@ class ColorBandFunction : public blender::fn::MultiFunction {
blender::fn::MFParams params,
blender::fn::MFContext UNUSED(context)) const override
{
- blender::fn::VSpan<float> values = params.readonly_single_input<float>(0, "Value");
+ const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
blender::MutableSpan<blender::Color4f> colors =
params.uninitialized_single_output<blender::Color4f>(1, "Color");
blender::MutableSpan<float> alphas = params.uninitialized_single_output<float>(2, "Alpha");