2021-03-21 19:31:24 +01:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
#include <optional>
|
|
|
|
|
2021-03-21 19:31:24 +01:00
|
|
|
#include "BLI_virtual_array.hh"
|
|
|
|
|
2021-10-14 11:06:18 -05:00
|
|
|
#include "FN_generic_array.hh"
|
2021-03-21 19:31:24 +01:00
|
|
|
#include "FN_generic_span.hh"
|
|
|
|
|
|
|
|
namespace blender::fn {
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
template<typename T> class GVArray_Typed;
|
|
|
|
template<typename T> class GVMutableArray_Typed;
|
|
|
|
|
2021-04-29 15:42:32 +02:00
|
|
|
class GVArray;
|
|
|
|
class GVMutableArray;
|
|
|
|
|
|
|
|
using GVArrayPtr = std::unique_ptr<GVArray>;
|
|
|
|
using GVMutableArrayPtr = std::unique_ptr<GVMutableArray>;
|
|
|
|
|
2021-03-21 19:31:24 +01:00
|
|
|
/* 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
|
|
|
|
{
|
2021-06-15 10:26:10 +02:00
|
|
|
return size_ == 0;
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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. */
|
2021-04-17 15:13:20 +02:00
|
|
|
GSpan get_internal_span() const
|
2021-03-21 19:31:24 +01:00
|
|
|
{
|
|
|
|
BLI_assert(this->is_span());
|
|
|
|
if (size_ == 0) {
|
|
|
|
return GSpan(*type_);
|
|
|
|
}
|
2021-04-17 15:13:20 +02:00
|
|
|
return this->get_internal_span_impl();
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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. */
|
2021-04-17 15:13:20 +02:00
|
|
|
void get_internal_single(void *r_value) const
|
2021-03-21 19:31:24 +01:00
|
|
|
{
|
|
|
|
BLI_assert(this->is_single());
|
|
|
|
if (size_ == 1) {
|
|
|
|
this->get(0, r_value);
|
2021-04-30 13:11:01 +02:00
|
|
|
return;
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
2021-04-17 15:13:20 +02:00
|
|
|
this->get_internal_single_impl(r_value);
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
/* Same as `get_internal_single`, but `r_value` points to initialized memory. */
|
2021-08-20 13:14:39 +02:00
|
|
|
void get_internal_single_to_uninitialized(void *r_value) const
|
2021-03-21 19:31:24 +01:00
|
|
|
{
|
2021-06-28 13:13:52 +02:00
|
|
|
type_->default_construct(r_value);
|
2021-04-17 15:13:20 +02:00
|
|
|
this->get_internal_single(r_value);
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
|
2021-05-10 10:28:24 +02:00
|
|
|
void materialize(void *dst) const;
|
|
|
|
void materialize(const IndexMask mask, void *dst) const;
|
|
|
|
|
2021-04-29 12:59:44 +02:00
|
|
|
void materialize_to_uninitialized(void *dst) const;
|
2021-03-21 19:31:24 +01:00
|
|
|
void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
template<typename T> const VArray<T> *try_get_internal_varray() const
|
|
|
|
{
|
|
|
|
BLI_assert(type_->is<T>());
|
|
|
|
return (const VArray<T> *)this->try_get_internal_varray_impl();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a typed virtual array for this generic virtual array. */
|
|
|
|
template<typename T> GVArray_Typed<T> typed() const
|
|
|
|
{
|
|
|
|
return GVArray_Typed<T>(*this);
|
|
|
|
}
|
|
|
|
|
2021-04-29 15:42:32 +02:00
|
|
|
GVArrayPtr shallow_copy() const;
|
|
|
|
|
2021-03-21 19:31:24 +01:00
|
|
|
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;
|
2021-04-17 15:13:20 +02:00
|
|
|
virtual GSpan get_internal_span_impl() const;
|
2021-03-21 19:31:24 +01:00
|
|
|
|
|
|
|
virtual bool is_single_impl() const;
|
2021-04-17 15:13:20 +02:00
|
|
|
virtual void get_internal_single_impl(void *UNUSED(r_value)) const;
|
|
|
|
|
2021-05-10 10:28:24 +02:00
|
|
|
virtual void materialize_impl(const IndexMask mask, void *dst) const;
|
2021-04-29 12:59:44 +02:00
|
|
|
virtual void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const;
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
virtual const void *try_get_internal_varray_impl() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Similar to GVArray, but supports changing the elements in the virtual array. */
|
|
|
|
class GVMutableArray : public GVArray {
|
|
|
|
public:
|
|
|
|
GVMutableArray(const CPPType &type, const int64_t size) : GVArray(type, size)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_by_copy(const int64_t index, const void *value)
|
|
|
|
{
|
|
|
|
BLI_assert(index >= 0);
|
|
|
|
BLI_assert(index < size_);
|
|
|
|
this->set_by_copy_impl(index, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_by_move(const int64_t index, void *value)
|
|
|
|
{
|
|
|
|
BLI_assert(index >= 0);
|
|
|
|
BLI_assert(index < size_);
|
|
|
|
this->set_by_move_impl(index, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_by_relocate(const int64_t index, void *value)
|
|
|
|
{
|
|
|
|
BLI_assert(index >= 0);
|
|
|
|
BLI_assert(index < size_);
|
|
|
|
this->set_by_relocate_impl(index, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
GMutableSpan get_internal_span()
|
|
|
|
{
|
|
|
|
BLI_assert(this->is_span());
|
|
|
|
GSpan span = static_cast<const GVArray *>(this)->get_internal_span();
|
|
|
|
return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> VMutableArray<T> *try_get_internal_mutable_varray()
|
|
|
|
{
|
|
|
|
BLI_assert(type_->is<T>());
|
|
|
|
return (VMutableArray<T> *)this->try_get_internal_mutable_varray_impl();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a typed virtual array for this generic virtual array. */
|
|
|
|
template<typename T> GVMutableArray_Typed<T> typed()
|
|
|
|
{
|
|
|
|
return GVMutableArray_Typed<T>(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void fill(const void *value);
|
|
|
|
|
2021-05-13 17:47:46 -05:00
|
|
|
/* Copy the values from the source buffer to all elements in the virtual array. */
|
|
|
|
void set_all(const void *src)
|
|
|
|
{
|
|
|
|
this->set_all_impl(src);
|
|
|
|
}
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
protected:
|
|
|
|
virtual void set_by_copy_impl(const int64_t index, const void *value);
|
|
|
|
virtual void set_by_relocate_impl(const int64_t index, void *value);
|
|
|
|
virtual void set_by_move_impl(const int64_t index, void *value) = 0;
|
|
|
|
|
2021-05-13 17:47:46 -05:00
|
|
|
virtual void set_all_impl(const void *src);
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
virtual void *try_get_internal_mutable_varray_impl();
|
2021-03-21 19:31:24 +01:00
|
|
|
};
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
class GVArray_For_GSpan : public GVArray {
|
2021-03-21 19:31:24 +01:00
|
|
|
protected:
|
2021-04-17 15:13:20 +02:00
|
|
|
const void *data_ = nullptr;
|
2021-03-21 19:31:24 +01:00
|
|
|
const int64_t element_size_;
|
|
|
|
|
|
|
|
public:
|
2021-04-17 15:13:20 +02:00
|
|
|
GVArray_For_GSpan(const GSpan span)
|
2021-03-21 19:31:24 +01:00
|
|
|
: GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2021-04-17 15:13:20 +02:00
|
|
|
GVArray_For_GSpan(const CPPType &type, const int64_t size)
|
|
|
|
: GVArray(type, size), element_size_(type.size())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-03-21 19:31:24 +01:00
|
|
|
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;
|
2021-04-17 15:13:20 +02:00
|
|
|
GSpan get_internal_span_impl() const override;
|
2021-03-21 19:31:24 +01:00
|
|
|
};
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
class GVArray_For_Empty : public GVArray {
|
2021-03-21 19:31:24 +01:00
|
|
|
public:
|
2021-04-17 15:13:20 +02:00
|
|
|
GVArray_For_Empty(const CPPType &type) : GVArray(type, 0)
|
2021-03-21 19:31:24 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void get_to_uninitialized_impl(const int64_t UNUSED(index), void *UNUSED(r_value)) const override
|
|
|
|
{
|
|
|
|
BLI_assert(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
class GVMutableArray_For_GMutableSpan : public GVMutableArray {
|
|
|
|
protected:
|
|
|
|
void *data_ = nullptr;
|
|
|
|
const int64_t element_size_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
GVMutableArray_For_GMutableSpan(const GMutableSpan span)
|
|
|
|
: GVMutableArray(span.type(), span.size()),
|
|
|
|
data_(span.data()),
|
|
|
|
element_size_(span.type().size())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
GVMutableArray_For_GMutableSpan(const CPPType &type, const int64_t size)
|
|
|
|
: GVMutableArray(type, size), element_size_(type.size())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_impl(const int64_t index, void *r_value) const override;
|
|
|
|
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
|
|
|
|
|
|
|
|
void set_by_copy_impl(const int64_t index, const void *value) override;
|
|
|
|
void set_by_move_impl(const int64_t index, void *value) override;
|
|
|
|
void set_by_relocate_impl(const int64_t index, void *value) override;
|
|
|
|
|
|
|
|
bool is_span_impl() const override;
|
|
|
|
GSpan get_internal_span_impl() const override;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Generic virtual array where each element has the same value. The value is not owned. */
|
|
|
|
class GVArray_For_SingleValueRef : public GVArray {
|
|
|
|
protected:
|
|
|
|
const void *value_ = nullptr;
|
2021-03-21 19:31:24 +01:00
|
|
|
|
|
|
|
public:
|
2021-04-17 15:13:20 +02:00
|
|
|
GVArray_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
|
2021-03-21 19:31:24 +01:00
|
|
|
: GVArray(type, size), value_(value)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2021-04-17 15:13:20 +02:00
|
|
|
GVArray_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArray(type, size)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-03-21 19:31:24 +01:00
|
|
|
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;
|
2021-04-17 15:13:20 +02:00
|
|
|
GSpan get_internal_span_impl() const override;
|
2021-03-21 19:31:24 +01:00
|
|
|
|
|
|
|
bool is_single_impl() const override;
|
2021-04-17 15:13:20 +02:00
|
|
|
void get_internal_single_impl(void *r_value) const override;
|
2021-03-21 19:31:24 +01:00
|
|
|
};
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
/* Same as GVArray_For_SingleValueRef, but the value is owned. */
|
|
|
|
class GVArray_For_SingleValue : public GVArray_For_SingleValueRef {
|
|
|
|
public:
|
|
|
|
GVArray_For_SingleValue(const CPPType &type, const int64_t size, const void *value);
|
|
|
|
~GVArray_For_SingleValue();
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Used to convert a typed virtual array into a generic one. */
|
|
|
|
template<typename T> class GVArray_For_VArray : public GVArray {
|
|
|
|
protected:
|
|
|
|
const VArray<T> *varray_ = nullptr;
|
2021-03-21 19:31:24 +01:00
|
|
|
|
|
|
|
public:
|
2021-04-17 15:13:20 +02:00
|
|
|
GVArray_For_VArray(const VArray<T> &varray)
|
|
|
|
: GVArray(CPPType::get<T>(), varray.size()), varray_(&varray)
|
2021-03-21 19:31:24 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2021-04-17 15:13:20 +02:00
|
|
|
GVArray_For_VArray(const int64_t size) : GVArray(CPPType::get<T>(), size)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-03-21 19:31:24 +01:00
|
|
|
void get_impl(const int64_t index, void *r_value) const override
|
|
|
|
{
|
2021-04-17 15:13:20 +02:00
|
|
|
*(T *)r_value = varray_->get(index);
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
|
|
|
|
{
|
2021-04-17 15:13:20 +02:00
|
|
|
new (r_value) T(varray_->get(index));
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool is_span_impl() const override
|
|
|
|
{
|
2021-04-17 15:13:20 +02:00
|
|
|
return varray_->is_span();
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
GSpan get_internal_span_impl() const override
|
2021-03-21 19:31:24 +01:00
|
|
|
{
|
2021-04-17 15:13:20 +02:00
|
|
|
return GSpan(varray_->get_internal_span());
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool is_single_impl() const override
|
|
|
|
{
|
2021-04-17 15:13:20 +02:00
|
|
|
return varray_->is_single();
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_internal_single_impl(void *r_value) const override
|
|
|
|
{
|
|
|
|
*(T *)r_value = varray_->get_internal_single();
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
|
2021-05-10 10:28:24 +02:00
|
|
|
void materialize_impl(const IndexMask mask, void *dst) const override
|
|
|
|
{
|
|
|
|
varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
|
|
|
|
}
|
|
|
|
|
2021-04-29 12:59:44 +02:00
|
|
|
void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override
|
|
|
|
{
|
|
|
|
varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
|
|
|
|
}
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
const void *try_get_internal_varray_impl() const override
|
2021-03-21 19:31:24 +01:00
|
|
|
{
|
2021-04-17 15:13:20 +02:00
|
|
|
return varray_;
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-10-14 11:06:18 -05:00
|
|
|
class GVArray_For_GArray : public GVArray_For_GSpan {
|
|
|
|
protected:
|
|
|
|
GArray<> array_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
GVArray_For_GArray(GArray<> array) : GVArray_For_GSpan(array.as_span()), array_(std::move(array))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
/* Used to convert any generic virtual array into a typed one. */
|
|
|
|
template<typename T> class VArray_For_GVArray : public VArray<T> {
|
|
|
|
protected:
|
|
|
|
const GVArray *varray_ = nullptr;
|
2021-03-21 19:31:24 +01:00
|
|
|
|
|
|
|
public:
|
2021-04-17 15:13:20 +02:00
|
|
|
VArray_For_GVArray(const GVArray &varray) : VArray<T>(varray.size()), varray_(&varray)
|
2021-03-21 19:31:24 +01:00
|
|
|
{
|
2021-04-17 15:13:20 +02:00
|
|
|
BLI_assert(varray_->type().template is<T>());
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2021-04-17 15:13:20 +02:00
|
|
|
VArray_For_GVArray(const int64_t size) : VArray<T>(size)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-03-21 19:31:24 +01:00
|
|
|
T get_impl(const int64_t index) const override
|
|
|
|
{
|
|
|
|
T value;
|
2021-04-17 15:13:20 +02:00
|
|
|
varray_->get(index, &value);
|
2021-03-21 19:31:24 +01:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_span_impl() const override
|
|
|
|
{
|
2021-04-17 15:13:20 +02:00
|
|
|
return varray_->is_span();
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
Span<T> get_internal_span_impl() const override
|
2021-03-21 19:31:24 +01:00
|
|
|
{
|
2021-04-17 15:13:20 +02:00
|
|
|
return varray_->get_internal_span().template typed<T>();
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool is_single_impl() const override
|
|
|
|
{
|
2021-04-17 15:13:20 +02:00
|
|
|
return varray_->is_single();
|
|
|
|
}
|
|
|
|
|
|
|
|
T get_internal_single_impl() const override
|
|
|
|
{
|
|
|
|
T value;
|
|
|
|
varray_->get_internal_single(&value);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Used to convert an generic mutable virtual array into a typed one. */
|
|
|
|
template<typename T> class VMutableArray_For_GVMutableArray : public VMutableArray<T> {
|
|
|
|
protected:
|
|
|
|
GVMutableArray *varray_ = nullptr;
|
|
|
|
|
|
|
|
public:
|
|
|
|
VMutableArray_For_GVMutableArray(GVMutableArray &varray)
|
|
|
|
: VMutableArray<T>(varray.size()), varray_(&varray)
|
|
|
|
{
|
|
|
|
BLI_assert(varray.type().template is<T>());
|
|
|
|
}
|
|
|
|
|
|
|
|
VMutableArray_For_GVMutableArray(const int64_t size) : VMutableArray<T>(size)
|
|
|
|
{
|
2021-03-21 19:31:24 +01:00
|
|
|
}
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
private:
|
|
|
|
T get_impl(const int64_t index) const override
|
2021-03-21 19:31:24 +01:00
|
|
|
{
|
|
|
|
T value;
|
2021-04-17 15:13:20 +02:00
|
|
|
varray_->get(index, &value);
|
2021-03-21 19:31:24 +01:00
|
|
|
return value;
|
|
|
|
}
|
2021-04-17 15:13:20 +02:00
|
|
|
|
|
|
|
void set_impl(const int64_t index, T value) override
|
|
|
|
{
|
|
|
|
varray_->set_by_relocate(index, &value);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_span_impl() const override
|
|
|
|
{
|
|
|
|
return varray_->is_span();
|
|
|
|
}
|
|
|
|
|
|
|
|
Span<T> get_internal_span_impl() const override
|
|
|
|
{
|
|
|
|
return varray_->get_internal_span().template typed<T>();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_single_impl() const override
|
|
|
|
{
|
|
|
|
return varray_->is_single();
|
|
|
|
}
|
|
|
|
|
|
|
|
T get_internal_single_impl() const override
|
|
|
|
{
|
|
|
|
T value;
|
|
|
|
varray_->get_internal_single(&value);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Used to convert any typed virtual mutable array into a generic one. */
|
|
|
|
template<typename T> class GVMutableArray_For_VMutableArray : public GVMutableArray {
|
|
|
|
protected:
|
|
|
|
VMutableArray<T> *varray_ = nullptr;
|
|
|
|
|
|
|
|
public:
|
|
|
|
GVMutableArray_For_VMutableArray(VMutableArray<T> &varray)
|
|
|
|
: GVMutableArray(CPPType::get<T>(), varray.size()), varray_(&varray)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
GVMutableArray_For_VMutableArray(const int64_t size) : GVMutableArray(CPPType::get<T>(), size)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_impl(const int64_t index, void *r_value) const override
|
|
|
|
{
|
|
|
|
*(T *)r_value = varray_->get(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
|
|
|
|
{
|
|
|
|
new (r_value) T(varray_->get(index));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_span_impl() const override
|
|
|
|
{
|
|
|
|
return varray_->is_span();
|
|
|
|
}
|
|
|
|
|
|
|
|
GSpan get_internal_span_impl() const override
|
|
|
|
{
|
|
|
|
Span<T> span = varray_->get_internal_span();
|
|
|
|
return span;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_single_impl() const override
|
|
|
|
{
|
|
|
|
return varray_->is_single();
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_internal_single_impl(void *r_value) const override
|
|
|
|
{
|
|
|
|
*(T *)r_value = varray_->get_internal_single();
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_by_copy_impl(const int64_t index, const void *value) override
|
|
|
|
{
|
|
|
|
const T &value_ = *(const T *)value;
|
|
|
|
varray_->set(index, value_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_by_relocate_impl(const int64_t index, void *value) override
|
|
|
|
{
|
|
|
|
T &value_ = *(T *)value;
|
|
|
|
varray_->set(index, std::move(value_));
|
|
|
|
value_.~T();
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_by_move_impl(const int64_t index, void *value) override
|
|
|
|
{
|
|
|
|
T &value_ = *(T *)value;
|
|
|
|
varray_->set(index, std::move(value_));
|
|
|
|
}
|
|
|
|
|
2021-05-16 11:19:04 +05:30
|
|
|
void set_all_impl(const void *src) override
|
2021-05-13 17:47:46 -05:00
|
|
|
{
|
2021-05-13 17:52:30 -05:00
|
|
|
varray_->set_all(Span((T *)src, size_));
|
2021-05-13 17:47:46 -05:00
|
|
|
}
|
|
|
|
|
2021-05-10 19:12:04 -05:00
|
|
|
void materialize_impl(const IndexMask mask, void *dst) const override
|
|
|
|
{
|
|
|
|
varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override
|
|
|
|
{
|
|
|
|
varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
|
|
|
|
}
|
|
|
|
|
2021-04-17 15:13:20 +02:00
|
|
|
const void *try_get_internal_varray_impl() const override
|
|
|
|
{
|
|
|
|
return (const VArray<T> *)varray_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *try_get_internal_mutable_varray_impl() override
|
|
|
|
{
|
|
|
|
return varray_;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* A generic version of VArray_Span. */
|
|
|
|
class GVArray_GSpan : public GSpan {
|
|
|
|
private:
|
|
|
|
const GVArray &varray_;
|
|
|
|
void *owned_data_ = nullptr;
|
|
|
|
|
|
|
|
public:
|
|
|
|
GVArray_GSpan(const GVArray &varray);
|
|
|
|
~GVArray_GSpan();
|
|
|
|
};
|
|
|
|
|
|
|
|
/* A generic version of VMutableArray_Span. */
|
|
|
|
class GVMutableArray_GSpan : public GMutableSpan {
|
|
|
|
private:
|
|
|
|
GVMutableArray &varray_;
|
|
|
|
void *owned_data_ = nullptr;
|
|
|
|
bool save_has_been_called_ = false;
|
|
|
|
bool show_not_saved_warning_ = true;
|
|
|
|
|
|
|
|
public:
|
|
|
|
GVMutableArray_GSpan(GVMutableArray &varray, bool copy_values_to_span = true);
|
|
|
|
~GVMutableArray_GSpan();
|
|
|
|
|
|
|
|
void save();
|
|
|
|
void disable_not_applied_warning();
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Similar to GVArray_GSpan, but the resulting span is typed. */
|
|
|
|
template<typename T> class GVArray_Span : public Span<T> {
|
|
|
|
private:
|
|
|
|
GVArray_GSpan varray_gspan_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
GVArray_Span(const GVArray &varray) : varray_gspan_(varray)
|
|
|
|
{
|
|
|
|
BLI_assert(varray.type().is<T>());
|
|
|
|
this->data_ = (const T *)varray_gspan_.data();
|
|
|
|
this->size_ = varray_gspan_.size();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T> class GVArray_For_OwnedVArray : public GVArray_For_VArray<T> {
|
|
|
|
private:
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
VArrayPtr<T> owned_varray_;
|
2021-04-17 15:13:20 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
/* Takes ownership of varray and passes a reference to the base class. */
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
GVArray_For_OwnedVArray(VArrayPtr<T> varray)
|
2021-04-17 15:13:20 +02:00
|
|
|
: GVArray_For_VArray<T>(*varray), owned_varray_(std::move(varray))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T> class VArray_For_OwnedGVArray : public VArray_For_GVArray<T> {
|
|
|
|
private:
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
GVArrayPtr owned_varray_;
|
2021-04-17 15:13:20 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
/* Takes ownership of varray and passes a reference to the base class. */
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
VArray_For_OwnedGVArray(GVArrayPtr varray)
|
2021-04-17 15:13:20 +02:00
|
|
|
: VArray_For_GVArray<T>(*varray), owned_varray_(std::move(varray))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
class GVMutableArray_For_OwnedVMutableArray : public GVMutableArray_For_VMutableArray<T> {
|
|
|
|
private:
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
VMutableArrayPtr<T> owned_varray_;
|
2021-04-17 15:13:20 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
/* Takes ownership of varray and passes a reference to the base class. */
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
GVMutableArray_For_OwnedVMutableArray(VMutableArrayPtr<T> varray)
|
2021-04-17 15:13:20 +02:00
|
|
|
: GVMutableArray_For_VMutableArray<T>(*varray), owned_varray_(std::move(varray))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
class VMutableArray_For_OwnedGVMutableArray : public VMutableArray_For_GVMutableArray<T> {
|
|
|
|
private:
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
GVMutableArrayPtr owned_varray_;
|
2021-04-17 15:13:20 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
/* Takes ownership of varray and passes a reference to the base class. */
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
VMutableArray_For_OwnedGVMutableArray(GVMutableArrayPtr varray)
|
2021-04-17 15:13:20 +02:00
|
|
|
: VMutableArray_For_GVMutableArray<T>(*varray), owned_varray_(std::move(varray))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Utility to embed a typed virtual array into a generic one. This avoids one allocation and give
|
|
|
|
* the compiler more opportunity to optimize the generic virtual array. */
|
|
|
|
template<typename T, typename VArrayT>
|
|
|
|
class GVArray_For_EmbeddedVArray : public GVArray_For_VArray<T> {
|
|
|
|
private:
|
|
|
|
VArrayT embedded_varray_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
template<typename... Args>
|
2021-07-30 16:19:19 +10:00
|
|
|
GVArray_For_EmbeddedVArray(const int64_t size, Args &&...args)
|
2021-04-17 15:13:20 +02:00
|
|
|
: GVArray_For_VArray<T>(size), embedded_varray_(std::forward<Args>(args)...)
|
|
|
|
{
|
|
|
|
this->varray_ = &embedded_varray_;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Same as GVArray_For_EmbeddedVArray, but for mutable virtual arrays. */
|
|
|
|
template<typename T, typename VMutableArrayT>
|
|
|
|
class GVMutableArray_For_EmbeddedVMutableArray : public GVMutableArray_For_VMutableArray<T> {
|
|
|
|
private:
|
|
|
|
VMutableArrayT embedded_varray_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
template<typename... Args>
|
2021-07-30 16:19:19 +10:00
|
|
|
GVMutableArray_For_EmbeddedVMutableArray(const int64_t size, Args &&...args)
|
2021-04-17 15:13:20 +02:00
|
|
|
: GVMutableArray_For_VMutableArray<T>(size), embedded_varray_(std::forward<Args>(args)...)
|
|
|
|
{
|
|
|
|
this->varray_ = &embedded_varray_;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Same as VArray_For_ArrayContainer, but for a generic virtual array. */
|
|
|
|
template<typename Container, typename T = typename Container::value_type>
|
|
|
|
class GVArray_For_ArrayContainer
|
|
|
|
: public GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>> {
|
|
|
|
public:
|
|
|
|
GVArray_For_ArrayContainer(Container container)
|
|
|
|
: GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>>(
|
|
|
|
container.size(), std::move(container))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Same as VArray_For_DerivedSpan, but for a generic virtual array. */
|
|
|
|
template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
|
|
|
|
class GVArray_For_DerivedSpan
|
|
|
|
: public GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>> {
|
|
|
|
public:
|
|
|
|
GVArray_For_DerivedSpan(const Span<StructT> data)
|
|
|
|
: GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>>(
|
|
|
|
data.size(), data)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Same as VMutableArray_For_DerivedSpan, but for a generic virtual array. */
|
|
|
|
template<typename StructT,
|
|
|
|
typename ElemT,
|
|
|
|
ElemT (*GetFunc)(const StructT &),
|
|
|
|
void (*SetFunc)(StructT &, ElemT)>
|
|
|
|
class GVMutableArray_For_DerivedSpan
|
|
|
|
: public GVMutableArray_For_EmbeddedVMutableArray<
|
|
|
|
ElemT,
|
|
|
|
VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>> {
|
|
|
|
public:
|
|
|
|
GVMutableArray_For_DerivedSpan(const MutableSpan<StructT> data)
|
|
|
|
: GVMutableArray_For_EmbeddedVMutableArray<
|
|
|
|
ElemT,
|
|
|
|
VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(data.size(), data)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Same as VArray_For_Span, but for a generic virtual array. */
|
|
|
|
template<typename T>
|
|
|
|
class GVArray_For_Span : public GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>> {
|
|
|
|
public:
|
|
|
|
GVArray_For_Span(const Span<T> data)
|
|
|
|
: GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>>(data.size(), data)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Same as VMutableArray_For_MutableSpan, but for a generic virtual array. */
|
|
|
|
template<typename T>
|
|
|
|
class GVMutableArray_For_MutableSpan
|
|
|
|
: public GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>> {
|
|
|
|
public:
|
|
|
|
GVMutableArray_For_MutableSpan(const MutableSpan<T> data)
|
|
|
|
: GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>>(data.size(),
|
|
|
|
data)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Utility class to create the "best" typed virtual array for a given generic virtual array.
|
|
|
|
* In most cases we don't just want to use VArray_For_GVArray, because it adds an additional
|
|
|
|
* indirection on element-access that can be avoided in many cases (e.g. when the virtual array is
|
|
|
|
* just a span or single value).
|
|
|
|
*
|
|
|
|
* This is not a virtual array itself, but is used to get a virtual array.
|
|
|
|
*/
|
|
|
|
template<typename T> class GVArray_Typed {
|
|
|
|
private:
|
|
|
|
const VArray<T> *varray_;
|
|
|
|
/* Of these optional virtual arrays, at most one is constructed at any time. */
|
|
|
|
std::optional<VArray_For_Span<T>> varray_span_;
|
|
|
|
std::optional<VArray_For_Single<T>> varray_single_;
|
|
|
|
std::optional<VArray_For_GVArray<T>> varray_any_;
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
GVArrayPtr owned_gvarray_;
|
2021-04-17 15:13:20 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
explicit GVArray_Typed(const GVArray &gvarray)
|
|
|
|
{
|
|
|
|
BLI_assert(gvarray.type().is<T>());
|
|
|
|
if (gvarray.is_span()) {
|
|
|
|
const GSpan span = gvarray.get_internal_span();
|
|
|
|
varray_span_.emplace(span.typed<T>());
|
|
|
|
varray_ = &*varray_span_;
|
|
|
|
}
|
|
|
|
else if (gvarray.is_single()) {
|
|
|
|
T single_value;
|
|
|
|
gvarray.get_internal_single(&single_value);
|
|
|
|
varray_single_.emplace(single_value, gvarray.size());
|
|
|
|
varray_ = &*varray_single_;
|
|
|
|
}
|
|
|
|
else if (const VArray<T> *internal_varray = gvarray.try_get_internal_varray<T>()) {
|
|
|
|
varray_ = internal_varray;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
varray_any_.emplace(gvarray);
|
|
|
|
varray_ = &*varray_any_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Same as the constructor above, but also takes ownership of the passed in virtual array. */
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
explicit GVArray_Typed(GVArrayPtr gvarray) : GVArray_Typed(*gvarray)
|
2021-04-17 15:13:20 +02:00
|
|
|
{
|
|
|
|
owned_gvarray_ = std::move(gvarray);
|
|
|
|
}
|
|
|
|
|
|
|
|
const VArray<T> &operator*() const
|
|
|
|
{
|
|
|
|
return *varray_;
|
|
|
|
}
|
|
|
|
|
|
|
|
const VArray<T> *operator->() const
|
|
|
|
{
|
|
|
|
return varray_;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Support implicit cast to the typed virtual array for convenience when `varray->typed<T>()` is
|
2021-06-24 15:56:58 +10:00
|
|
|
* used within an expression. */
|
2021-04-17 15:13:20 +02:00
|
|
|
operator const VArray<T> &() const
|
|
|
|
{
|
|
|
|
return *varray_;
|
|
|
|
}
|
|
|
|
|
|
|
|
T operator[](const int64_t index) const
|
|
|
|
{
|
|
|
|
return varray_->get(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t size() const
|
|
|
|
{
|
|
|
|
return varray_->size();
|
|
|
|
}
|
|
|
|
|
|
|
|
IndexRange index_range() const
|
|
|
|
{
|
|
|
|
return IndexRange(this->size());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Same as GVArray_Typed, but for mutable virtual arrays. */
|
|
|
|
template<typename T> class GVMutableArray_Typed {
|
|
|
|
private:
|
|
|
|
VMutableArray<T> *varray_;
|
|
|
|
std::optional<VMutableArray_For_MutableSpan<T>> varray_span_;
|
|
|
|
std::optional<VMutableArray_For_GVMutableArray<T>> varray_any_;
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
GVMutableArrayPtr owned_gvarray_;
|
2021-04-17 15:13:20 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
explicit GVMutableArray_Typed(GVMutableArray &gvarray)
|
|
|
|
{
|
|
|
|
BLI_assert(gvarray.type().is<T>());
|
|
|
|
if (gvarray.is_span()) {
|
|
|
|
const GMutableSpan span = gvarray.get_internal_span();
|
|
|
|
varray_span_.emplace(span.typed<T>());
|
|
|
|
varray_ = &*varray_span_;
|
|
|
|
}
|
|
|
|
else if (VMutableArray<T> *internal_varray = gvarray.try_get_internal_mutable_varray<T>()) {
|
|
|
|
varray_ = internal_varray;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
varray_any_.emplace(gvarray);
|
|
|
|
varray_ = &*varray_any_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
explicit GVMutableArray_Typed(GVMutableArrayPtr gvarray) : GVMutableArray_Typed(*gvarray)
|
2021-04-17 15:13:20 +02:00
|
|
|
{
|
|
|
|
owned_gvarray_ = std::move(gvarray);
|
|
|
|
}
|
|
|
|
|
|
|
|
VMutableArray<T> &operator*()
|
|
|
|
{
|
|
|
|
return *varray_;
|
|
|
|
}
|
|
|
|
|
|
|
|
VMutableArray<T> *operator->()
|
|
|
|
{
|
|
|
|
return varray_;
|
|
|
|
}
|
|
|
|
|
|
|
|
operator VMutableArray<T> &()
|
|
|
|
{
|
|
|
|
return *varray_;
|
|
|
|
}
|
|
|
|
|
|
|
|
T operator[](const int64_t index) const
|
|
|
|
{
|
|
|
|
return varray_->get(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t size() const
|
|
|
|
{
|
|
|
|
return varray_->size();
|
|
|
|
}
|
2021-03-21 19:31:24 +01:00
|
|
|
};
|
|
|
|
|
2021-09-15 11:02:39 +02:00
|
|
|
class GVArray_For_SlicedGVArray : public GVArray {
|
|
|
|
protected:
|
|
|
|
const GVArray &varray_;
|
|
|
|
int64_t offset_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
GVArray_For_SlicedGVArray(const GVArray &varray, const IndexRange slice)
|
|
|
|
: GVArray(varray.type(), slice.size()), varray_(varray), offset_(slice.start())
|
|
|
|
{
|
|
|
|
BLI_assert(slice.one_after_last() <= varray.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: Add #materialize method. */
|
|
|
|
void get_impl(const int64_t index, void *r_value) const override;
|
|
|
|
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Utility class to create the "best" sliced virtual array.
|
|
|
|
*/
|
|
|
|
class GVArray_Slice {
|
|
|
|
private:
|
|
|
|
const GVArray *varray_;
|
|
|
|
/* Of these optional virtual arrays, at most one is constructed at any time. */
|
|
|
|
std::optional<GVArray_For_GSpan> varray_span_;
|
|
|
|
std::optional<GVArray_For_SlicedGVArray> varray_any_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
GVArray_Slice(const GVArray &varray, const IndexRange slice);
|
|
|
|
|
|
|
|
const GVArray &operator*()
|
|
|
|
{
|
|
|
|
return *varray_;
|
|
|
|
}
|
|
|
|
|
|
|
|
const GVArray *operator->()
|
|
|
|
{
|
|
|
|
return varray_;
|
|
|
|
}
|
|
|
|
|
|
|
|
operator const GVArray &()
|
|
|
|
{
|
|
|
|
return *varray_;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-03-21 19:31:24 +01:00
|
|
|
} // namespace blender::fn
|