diff options
-rw-r--r-- | source/blender/functions/FN_array_spans.hh | 185 | ||||
-rw-r--r-- | source/blender/functions/FN_cpp_type.hh | 2 | ||||
-rw-r--r-- | source/blender/functions/FN_generic_vector_array.hh | 27 | ||||
-rw-r--r-- | source/blender/functions/FN_multi_function_data_type.hh | 2 | ||||
-rw-r--r-- | source/blender/functions/FN_multi_function_param_type.hh | 10 | ||||
-rw-r--r-- | source/blender/functions/FN_multi_function_params.hh | 4 | ||||
-rw-r--r-- | source/blender/functions/FN_multi_function_signature.hh | 4 | ||||
-rw-r--r-- | source/blender/functions/FN_spans.hh | 221 | ||||
-rw-r--r-- | tests/gtests/functions/FN_array_spans_test.cc | 57 | ||||
-rw-r--r-- | tests/gtests/functions/FN_generic_vector_array_test.cc | 17 | ||||
-rw-r--r-- | tests/gtests/functions/FN_spans_test.cc | 72 |
11 files changed, 399 insertions, 202 deletions
diff --git a/source/blender/functions/FN_array_spans.hh b/source/blender/functions/FN_array_spans.hh index ca818ad6b11..fac2ef42c9d 100644 --- a/source/blender/functions/FN_array_spans.hh +++ b/source/blender/functions/FN_array_spans.hh @@ -30,22 +30,18 @@ namespace blender { namespace fn { /** - * 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. + * Depending on the use case, the referenced data might have a different structure. More + * categories can be added when necessary. */ -template<typename T> class VArraySpan { - private: - /** - * Depending on the use case, the referenced data might have a different structure. More - * categories can be added when necessary. - */ - enum Category { - SingleArray, - StartsAndSizes, - }; +enum class VArraySpanCategory { + SingleArray, + StartsAndSizes, +}; +template<typename T> class VArraySpanBase { + protected: uint m_virtual_size; - Category m_category; + VArraySpanCategory m_category; union { struct { @@ -59,50 +55,77 @@ template<typename T> class VArraySpan { } m_data; public: - VArraySpan() + bool is_single_array() const { - m_virtual_size = 0; - m_category = StartsAndSizes; - m_data.starts_and_sizes.starts = nullptr; - m_data.starts_and_sizes.sizes = nullptr; + switch (m_category) { + case VArraySpanCategory::SingleArray: + return true; + case VArraySpanCategory::StartsAndSizes: + return m_virtual_size == 1; + } + BLI_assert(false); + return false; } - VArraySpan(Span<T> span, uint virtual_size) + bool is_empty() const { - m_virtual_size = virtual_size; - m_category = SingleArray; - m_data.single_array.start = span.data(); - m_data.single_array.size = span.size(); + return this->m_virtual_size == 0; } - VArraySpan(Span<const T *> starts, Span<uint> sizes) + uint size() const { - BLI_assert(starts.size() == sizes.size()); - m_virtual_size = starts.size(); - m_category = StartsAndSizes; - m_data.starts_and_sizes.starts = starts.begin(); - m_data.starts_and_sizes.sizes = sizes.begin(); + return this->m_virtual_size; } +}; - bool is_empty() const +/** + * 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) { - return m_virtual_size == 0; + memcpy(this, &other, sizeof(VArraySpanBase<void>)); } - uint size() const + public: + VArraySpan() + { + this->m_virtual_size = 0; + this->m_category = VArraySpanCategory::StartsAndSizes; + this->m_data.starts_and_sizes.starts = nullptr; + this->m_data.starts_and_sizes.sizes = nullptr; + } + + VArraySpan(Span<T> span, uint virtual_size) { - return m_virtual_size; + this->m_virtual_size = virtual_size; + this->m_category = VArraySpanCategory::SingleArray; + this->m_data.single_array.start = span.data(); + this->m_data.single_array.size = span.size(); + } + + VArraySpan(Span<const T *> starts, Span<uint> sizes) + { + BLI_assert(starts.size() == sizes.size()); + this->m_virtual_size = starts.size(); + this->m_category = VArraySpanCategory::StartsAndSizes; + this->m_data.starts_and_sizes.starts = starts.begin(); + this->m_data.starts_and_sizes.sizes = sizes.begin(); } VSpan<T> operator[](uint index) const { - BLI_assert(index < m_virtual_size); - switch (m_category) { - case SingleArray: - return VSpan<T>(Span<T>(m_data.single_array.start, m_data.single_array.size)); - case StartsAndSizes: - return VSpan<T>( - Span<T>(m_data.starts_and_sizes.starts[index], m_data.starts_and_sizes.sizes[index])); + BLI_assert(index < this->m_virtual_size); + switch (this->m_category) { + case VArraySpanCategory::SingleArray: + return VSpan<T>(Span<T>(this->m_data.single_array.start, this->m_data.single_array.size)); + case VArraySpanCategory::StartsAndSizes: + return VSpan<T>(Span<T>(this->m_data.starts_and_sizes.starts[index], + this->m_data.starts_and_sizes.sizes[index])); } BLI_assert(false); return {}; @@ -113,99 +136,65 @@ template<typename T> class VArraySpan { * A generic virtual array span. It's just like a VArraySpan, but the type is only known at * run-time. */ -class GVArraySpan { +class GVArraySpan : public VArraySpanBase<void> { private: - /** - * Depending on the use case, the referenced data might have a different structure. More - * categories can be added when necessary. - */ - enum Category { - SingleArray, - StartsAndSizes, - }; - const CPPType *m_type; - uint m_virtual_size; - Category m_category; - - union { - struct { - const void *values; - uint size; - } single_array; - struct { - const void *const *starts; - const uint *sizes; - } starts_and_sizes; - } m_data; GVArraySpan() = default; public: GVArraySpan(const CPPType &type) { - m_type = &type; - m_virtual_size = 0; - m_category = StartsAndSizes; - m_data.starts_and_sizes.starts = nullptr; - m_data.starts_and_sizes.sizes = nullptr; + this->m_type = &type; + this->m_virtual_size = 0; + this->m_category = VArraySpanCategory::StartsAndSizes; + this->m_data.starts_and_sizes.starts = nullptr; + this->m_data.starts_and_sizes.sizes = nullptr; } GVArraySpan(GSpan array, uint virtual_size) { - m_type = &array.type(); - m_virtual_size = virtual_size; - m_category = SingleArray; - m_data.single_array.values = array.buffer(); - m_data.single_array.size = array.size(); + this->m_type = &array.type(); + this->m_virtual_size = virtual_size; + this->m_category = VArraySpanCategory::SingleArray; + this->m_data.single_array.start = array.buffer(); + this->m_data.single_array.size = array.size(); } GVArraySpan(const CPPType &type, Span<const void *> starts, Span<uint> sizes) { BLI_assert(starts.size() == sizes.size()); - m_type = &type; - m_virtual_size = starts.size(); - m_category = StartsAndSizes; - m_data.starts_and_sizes.starts = starts.begin(); - m_data.starts_and_sizes.sizes = sizes.begin(); - } - - bool is_empty() const - { - return m_virtual_size == 0; + this->m_type = &type; + this->m_virtual_size = starts.size(); + this->m_category = VArraySpanCategory::StartsAndSizes; + this->m_data.starts_and_sizes.starts = (void **)starts.begin(); + this->m_data.starts_and_sizes.sizes = sizes.begin(); } - uint size() const + template<typename T> GVArraySpan(VArraySpan<T> other) { - return m_virtual_size; + this->m_type = &CPPType::get<T>(); + memcpy(this, &other, sizeof(VArraySpanBase<void>)); } const CPPType &type() const { - return *m_type; + return *this->m_type; } template<typename T> VArraySpan<T> typed() const { BLI_assert(CPPType::get<T>() == *m_type); - switch (m_category) { - case SingleArray: - return VArraySpan<T>( - Span<T>((const T *)m_data.single_array.values, m_data.single_array.size)); - case StartsAndSizes: - return VArraySpan<T>( - Span<const T *>((const T *const *)m_data.starts_and_sizes.starts, m_virtual_size), - Span<uint>(m_data.starts_and_sizes.sizes, m_virtual_size)); - } + return VArraySpan<T>(*this); } GVSpan operator[](uint index) const { BLI_assert(index < m_virtual_size); switch (m_category) { - case SingleArray: - return GVSpan(GSpan(*m_type, m_data.single_array.values, m_data.single_array.size)); - case StartsAndSizes: + case VArraySpanCategory::SingleArray: + return GVSpan(GSpan(*m_type, m_data.single_array.start, m_data.single_array.size)); + case VArraySpanCategory::StartsAndSizes: return GVSpan(GSpan( *m_type, m_data.starts_and_sizes.starts[index], m_data.starts_and_sizes.sizes[index])); } diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh index df5218ed5ba..c6e440251ee 100644 --- a/source/blender/functions/FN_cpp_type.hh +++ b/source/blender/functions/FN_cpp_type.hh @@ -725,6 +725,8 @@ static std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &d const blender::fn::CPPType &CPPType_##IDENTIFIER = *CPPTYPE_##IDENTIFIER##_owner; \ template<> const blender::fn::CPPType &blender::fn::CPPType::get<TYPE_NAME>() \ { \ + /* This can happen when trying to access a CPPType during static storage initialization. */ \ + BLI_assert(CPPTYPE_##IDENTIFIER##_owner.get() != nullptr); \ return CPPType_##IDENTIFIER; \ } diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/functions/FN_generic_vector_array.hh index 90c0fbad136..1c8f74f2abe 100644 --- a/source/blender/functions/FN_generic_vector_array.hh +++ b/source/blender/functions/FN_generic_vector_array.hh @@ -119,6 +119,23 @@ class GVectorArray : NonCopyable, NonMovable { m_lengths[index]++; } + void extend(uint index, GVSpan span) + { + BLI_assert(m_type == span.type()); + for (uint i = 0; i < span.size(); i++) { + this->append(index, span[i]); + } + } + + void extend(IndexMask mask, GVArraySpan array_span) + { + BLI_assert(m_type == array_span.type()); + BLI_assert(mask.min_array_size() <= array_span.size()); + for (uint i : mask) { + this->extend(i, array_span[i]); + } + } + GMutableSpan operator[](uint index) { BLI_assert(index < m_starts.size()); @@ -158,6 +175,16 @@ template<typename T> class GVectorArrayRef { m_vector_array->append(index, &value); } + void extend(uint index, Span<T> values) + { + m_vector_array->extend(index, values); + } + + void extend(uint index, VSpan<T> values) + { + m_vector_array->extend(index, GVSpan(values)); + } + MutableSpan<T> operator[](uint index) { BLI_assert(index < m_vector_array->m_starts.size()); diff --git a/source/blender/functions/FN_multi_function_data_type.hh b/source/blender/functions/FN_multi_function_data_type.hh index 856d1cc7253..1a7b179c6ae 100644 --- a/source/blender/functions/FN_multi_function_data_type.hh +++ b/source/blender/functions/FN_multi_function_data_type.hh @@ -46,6 +46,8 @@ class MFDataType { } public: + MFDataType() = default; + static MFDataType ForSingle(const CPPType &type) { return MFDataType(Single, type); diff --git a/source/blender/functions/FN_multi_function_param_type.hh b/source/blender/functions/FN_multi_function_param_type.hh index bd31a793b21..d89c13505f9 100644 --- a/source/blender/functions/FN_multi_function_param_type.hh +++ b/source/blender/functions/FN_multi_function_param_type.hh @@ -135,6 +135,16 @@ class MFParamType { return SingleInput; } + bool is_input_or_mutable() const + { + return ELEM(m_interface_type, Input, Mutable); + } + + bool is_output_or_mutable() const + { + return ELEM(m_interface_type, Output, Mutable); + } + friend bool operator==(const MFParamType &a, const MFParamType &b); friend bool operator!=(const MFParamType &a, const MFParamType &b); }; diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh index 2388e3b15e5..6a0eb698250 100644 --- a/source/blender/functions/FN_multi_function_params.hh +++ b/source/blender/functions/FN_multi_function_params.hh @@ -199,6 +199,10 @@ class MFParams { return m_builder->m_mutable_spans[data_index]; } + template<typename T> GVectorArrayRef<T> vector_mutable(uint param_index, StringRef name = "") + { + return this->vector_mutable(param_index, name).typed<T>(); + } GVectorArray &vector_mutable(uint param_index, StringRef name = "") { this->assert_correct_param(param_index, name, MFParamType::VectorMutable); diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh index 64bbd7be5c8..73e7b9bb18d 100644 --- a/source/blender/functions/FN_multi_function_signature.hh +++ b/source/blender/functions/FN_multi_function_signature.hh @@ -135,6 +135,10 @@ class MFSignatureBuilder { { this->mutable_(name, MFDataType::ForSingle(type)); } + template<typename T> void vector_mutable(StringRef name) + { + this->vector_mutable(name, CPPType::get<T>()); + } void vector_mutable(StringRef name, const CPPType &base_type) { this->mutable_(name, MFDataType::ForVector(base_type)); diff --git a/source/blender/functions/FN_spans.hh b/source/blender/functions/FN_spans.hh index c206662231c..d3497c05eb9 100644 --- a/source/blender/functions/FN_spans.hh +++ b/source/blender/functions/FN_spans.hh @@ -68,7 +68,7 @@ class GSpan { } template<typename T> - GSpan(Span<T> array) : GSpan(CPPType::get<T>(), (const void *)array.begin(), array.size()) + GSpan(Span<T> array) : GSpan(CPPType::get<T>(), (const void *)array.data(), array.size()) { } @@ -171,21 +171,16 @@ class GMutableSpan { } }; -/** - * 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 { - private: - enum Category { - Single, - FullArray, - FullPointerArray, - }; +enum class VSpanCategory { + Single, + FullArray, + FullPointerArray, +}; +template<typename T> struct VSpanBase { + protected: uint m_virtual_size; - Category m_category; - + VSpanCategory m_category; union { struct { const T *data; @@ -199,18 +194,59 @@ template<typename T> class VSpan { } m_data; public: + bool is_single_element() const + { + switch (m_category) { + case VSpanCategory::Single: + return true; + case VSpanCategory::FullArray: + return m_virtual_size == 1; + case VSpanCategory::FullPointerArray: + return m_virtual_size == 1; + } + BLI_assert(false); + return false; + } + + bool is_empty() const + { + return this->m_virtual_size == 0; + } + + uint size() const + { + return this->m_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() { - m_virtual_size = 0; - m_category = FullArray; - m_data.full_array.data = nullptr; + this->m_virtual_size = 0; + this->m_category = VSpanCategory::FullArray; + this->m_data.full_array.data = nullptr; } VSpan(Span<T> values) { - m_virtual_size = values.size(); - m_category = FullArray; - m_data.full_array.data = values.begin(); + this->m_virtual_size = values.size(); + this->m_category = VSpanCategory::FullArray; + this->m_data.full_array.data = values.begin(); } VSpan(MutableSpan<T> values) : VSpan(Span<T>(values)) @@ -219,43 +255,33 @@ template<typename T> class VSpan { VSpan(Span<const T *> values) { - m_virtual_size = values.size(); - m_category = FullPointerArray; - m_data.full_pointer_array.data = values.begin(); + this->m_virtual_size = values.size(); + this->m_category = VSpanCategory::FullPointerArray; + this->m_data.full_pointer_array.data = values.begin(); } static VSpan FromSingle(const T *value, uint virtual_size) { VSpan ref; ref.m_virtual_size = virtual_size; - ref.m_category = Single; + ref.m_category = VSpanCategory::Single; ref.m_data.single.data = value; return ref; } const T &operator[](uint index) const { - BLI_assert(index < m_virtual_size); - switch (m_category) { - case Single: - return *m_data.single.data; - case FullArray: - return m_data.full_array.data[index]; - case FullPointerArray: - return *m_data.full_pointer_array.data[index]; + BLI_assert(index < this->m_virtual_size); + switch (this->m_category) { + case VSpanCategory::Single: + return *this->m_data.single.data; + case VSpanCategory::FullArray: + return this->m_data.full_array.data[index]; + case VSpanCategory::FullPointerArray: + return *this->m_data.full_pointer_array.data[index]; } BLI_assert(false); - return *m_data.single.data; - } - - bool is_empty() const - { - return m_virtual_size == 0; - } - - uint size() const - { - return m_virtual_size; + return *this->m_data.single.data; } }; @@ -263,53 +289,39 @@ template<typename T> class VSpan { * 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 { +class GVSpan : public VSpanBase<void> { private: - enum Category { - Single, - FullArray, - FullPointerArray, - }; - const CPPType *m_type; - uint m_virtual_size; - Category m_category; - - union { - struct { - const void *data; - } single; - struct { - const void *data; - } full_array; - struct { - const void *const *data; - } full_pointer_array; - } m_data; GVSpan() = default; public: GVSpan(const CPPType &type) { - m_type = &type; - m_virtual_size = 0; - m_category = FullArray; - m_data.full_array.data = nullptr; + this->m_type = &type; + this->m_virtual_size = 0; + this->m_category = VSpanCategory::FullArray; + this->m_data.full_array.data = nullptr; } GVSpan(GSpan values) { - m_type = &values.type(); - m_virtual_size = values.size(); - m_category = FullArray; - m_data.full_array.data = values.buffer(); + this->m_type = &values.type(); + this->m_virtual_size = values.size(); + this->m_category = VSpanCategory::FullArray; + this->m_data.full_array.data = values.buffer(); } GVSpan(GMutableSpan values) : GVSpan(GSpan(values)) { } + template<typename T> GVSpan(const VSpanBase<T> &values) + { + this->m_type = &CPPType::get<T>(); + memcpy(this, &values, sizeof(VSpanBase<void>)); + } + template<typename T> GVSpan(Span<T> values) : GVSpan(GSpan(values)) { } @@ -323,7 +335,7 @@ class GVSpan { GVSpan ref; ref.m_type = &type; ref.m_virtual_size = virtual_size; - ref.m_category = Single; + ref.m_category = VSpanCategory::Single; ref.m_data.single.data = value; return ref; } @@ -333,55 +345,56 @@ class GVSpan { GVSpan ref; ref.m_type = &type; ref.m_virtual_size = size; - ref.m_category = FullPointerArray; + ref.m_category = VSpanCategory::FullPointerArray; ref.m_data.full_pointer_array.data = values; return ref; } - bool is_empty() const - { - return m_virtual_size == 0; - } - - uint size() const - { - return m_virtual_size; - } - const CPPType &type() const { - return *m_type; + return *this->m_type; } const void *operator[](uint index) const { - BLI_assert(index < m_virtual_size); - switch (m_category) { - case Single: - return m_data.single.data; - case FullArray: - return POINTER_OFFSET(m_data.full_array.data, index * m_type->size()); - case FullPointerArray: - return m_data.full_pointer_array.data[index]; + BLI_assert(index < this->m_virtual_size); + switch (this->m_category) { + case VSpanCategory::Single: + return this->m_data.single.data; + case VSpanCategory::FullArray: + return POINTER_OFFSET(this->m_data.full_array.data, index * m_type->size()); + case VSpanCategory::FullPointerArray: + return this->m_data.full_pointer_array.data[index]; } BLI_assert(false); - return m_data.single.data; + return this->m_data.single.data; } template<typename T> VSpan<T> typed() const { BLI_assert(CPPType::get<T>() == *m_type); - switch (m_category) { - case Single: - return VSpan<T>::FromSingle((const T *)m_data.single.data, m_virtual_size); - case FullArray: - return VSpan<T>(Span<T>((const T *)m_data.full_array.data, m_virtual_size)); - case FullPointerArray: - return VSpan<T>( - Span<const T *>((const T *const *)m_data.full_pointer_array.data, m_virtual_size)); + return VSpan<T>(*this); + } + + const void *as_single_element() const + { + BLI_assert(this->is_single_element()); + return (*this)[0]; + } + + void materialize_to_uninitialized(void *dst) const + { + this->materialize_to_uninitialized(IndexRange(m_virtual_size), dst); + } + + void materialize_to_uninitialized(IndexMask mask, void *dst) const + { + BLI_assert(this->size() >= mask.min_array_size()); + + uint element_size = m_type->size(); + for (uint i : mask) { + m_type->copy_to_uninitialized((*this)[i], POINTER_OFFSET(dst, element_size * i)); } - BLI_assert(false); - return {}; } }; diff --git a/tests/gtests/functions/FN_array_spans_test.cc b/tests/gtests/functions/FN_array_spans_test.cc index 47e1c129266..21e52a90e4b 100644 --- a/tests/gtests/functions/FN_array_spans_test.cc +++ b/tests/gtests/functions/FN_array_spans_test.cc @@ -18,6 +18,9 @@ #include "FN_array_spans.hh" #include "FN_cpp_types.hh" +#include "FN_generic_vector_array.hh" + +#include "BLI_array.hh" namespace blender { namespace fn { @@ -27,6 +30,10 @@ 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) @@ -44,6 +51,13 @@ TEST(virtual_array_span, SingleArrayConstructor) 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) @@ -65,6 +79,15 @@ TEST(virtual_array_span, MultipleArrayConstructor) 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) @@ -72,6 +95,9 @@ TEST(generic_virtual_array_span, TypeConstructor) GVArraySpan span{CPPType_int32}; 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) @@ -86,6 +112,37 @@ TEST(generic_virtual_array_span, GSpanConstructor) 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_int32, 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 fn diff --git a/tests/gtests/functions/FN_generic_vector_array_test.cc b/tests/gtests/functions/FN_generic_vector_array_test.cc index 5840feb955d..c701fb9f678 100644 --- a/tests/gtests/functions/FN_generic_vector_array_test.cc +++ b/tests/gtests/functions/FN_generic_vector_array_test.cc @@ -97,5 +97,22 @@ TEST(generic_vector_array, TypedRef) EXPECT_EQ(ref[3][1], 6); } +TEST(generic_vector_array, Extend) +{ + GVectorArray vectors{CPPType_int32, 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); +} + } // namespace fn } // namespace blender diff --git a/tests/gtests/functions/FN_spans_test.cc b/tests/gtests/functions/FN_spans_test.cc index 551918a3aae..59797f69309 100644 --- a/tests/gtests/functions/FN_spans_test.cc +++ b/tests/gtests/functions/FN_spans_test.cc @@ -71,6 +71,11 @@ TEST(virtual_span, EmptyConstructor) VSpan<int> span; EXPECT_EQ(span.size(), 0); EXPECT_TRUE(span.is_empty()); + EXPECT_FALSE(span.is_single_element()); + + GVSpan converted(span); + EXPECT_EQ(converted.type(), CPPType::get<int>()); + EXPECT_EQ(converted.size(), 0); } TEST(virtual_span, SpanConstructor) @@ -83,6 +88,11 @@ TEST(virtual_span, SpanConstructor) 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()); + + GVSpan converted(span); + EXPECT_EQ(converted.type(), CPPType::get<int>()); + EXPECT_EQ(converted.size(), 5); } TEST(virtual_span, PointerSpanConstructor) @@ -98,6 +108,14 @@ TEST(virtual_span, PointerSpanConstructor) EXPECT_EQ(span[1], 7); EXPECT_EQ(span[2], 6); EXPECT_EQ(&span[1], &x2); + EXPECT_FALSE(span.is_single_element()); + + 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) @@ -112,6 +130,14 @@ TEST(virtual_span, SingleConstructor) EXPECT_EQ(&span[0], &value); EXPECT_EQ(&span[1], &value); EXPECT_EQ(&span[2], &value); + EXPECT_TRUE(span.is_single_element()); + + 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) @@ -119,6 +145,10 @@ TEST(generic_virtual_span, TypeConstructor) GVSpan span(CPPType_int32); EXPECT_EQ(span.size(), 0); EXPECT_TRUE(span.is_empty()); + EXPECT_FALSE(span.is_single_element()); + + VSpan<int> converted = span.typed<int>(); + EXPECT_EQ(converted.size(), 0); } TEST(generic_virtual_span, GenericSpanConstructor) @@ -131,6 +161,21 @@ TEST(generic_virtual_span, GenericSpanConstructor) EXPECT_EQ(span[1], &values[1]); EXPECT_EQ(span[2], &values[2]); EXPECT_EQ(span[3], &values[3]); + EXPECT_FALSE(span.is_single_element()); + + 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) @@ -142,6 +187,19 @@ TEST(generic_virtual_span, SpanConstructor) EXPECT_EQ(span[0], &values[0]); EXPECT_EQ(span[1], &values[1]); EXPECT_EQ(span[2], &values[2]); + EXPECT_FALSE(span.is_single_element()); + + 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) @@ -153,6 +211,20 @@ TEST(generic_virtual_span, SingleConstructor) 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); + + 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 fn |