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:
authorJacques Lucke <jacques@blender.org>2021-03-21 21:31:24 +0300
committerJacques Lucke <jacques@blender.org>2021-03-21 21:33:13 +0300
commit4fe8d0419c2f080a248f52b3924ce2a4e897e5cb (patch)
tree81aba45e26cca99578087835184ce5664362b791 /source/blender/functions
parent68c31c41e52caa1ac5b527f835b16f8e298dfd86 (diff)
Functions: refactor virtual array data structures
When a function is executed for many elements (e.g. per point) it is often the case that some parameters are different for every element and other parameters are the same (there are some more less common cases). To simplify writing such functions one can use a "virtual array". This is a data structure that has a value for every index, but might not be stored as an actual array internally. Instead, it might be just a single value or is computed on the fly. There are various tradeoffs involved when using this data structure which are mentioned in `BLI_virtual_array.hh`. It is called "virtual", because it uses inheritance and virtual methods. Furthermore, there is a new virtual vector array data structure, which is an array of vectors. Both these types have corresponding generic variants, which can be used when the data type is not known at compile time. This is typically the case when building a somewhat generic execution system. The function system used these virtual data structures before, but now they are more versatile. I've done this refactor in preparation for the attribute processor and other features of geometry nodes. I moved the typed virtual arrays to blenlib, so that they can be used independent of the function system. One open question for me is whether all the generic data structures (and `CPPType`) should be moved to blenlib as well. They are well isolated and don't really contain any business logic. That can be done later if necessary.
Diffstat (limited to 'source/blender/functions')
-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
20 files changed, 1300 insertions, 1407 deletions
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