Creating a shallow copy is sometimes useful to get a unique ptr for a virtual array when one only has a reference. It shouldn't be used usually, but sometimes its the fastest way to do correct ownership handling.
		
			
				
	
	
		
			882 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			882 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License
 | |
|  * as published by the Free Software Foundation; either version 2
 | |
|  * of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software Foundation,
 | |
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | |
|  */
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| /** \file
 | |
|  * \ingroup fn
 | |
|  *
 | |
|  * A generic virtual array is the same as a virtual array from blenlib, except for the fact that
 | |
|  * the data type is only known at runtime.
 | |
|  */
 | |
| 
 | |
| #include <optional>
 | |
| 
 | |
| #include "BLI_virtual_array.hh"
 | |
| 
 | |
| #include "FN_generic_span.hh"
 | |
| 
 | |
| namespace blender::fn {
 | |
| 
 | |
| template<typename T> class GVArray_Typed;
 | |
| template<typename T> class GVMutableArray_Typed;
 | |
| 
 | |
| class GVArray;
 | |
| class GVMutableArray;
 | |
| 
 | |
| using GVArrayPtr = std::unique_ptr<GVArray>;
 | |
| using GVMutableArrayPtr = std::unique_ptr<GVMutableArray>;
 | |
| 
 | |
| /* A generically typed version of `VArray<T>`. */
 | |
| class GVArray {
 | |
|  protected:
 | |
|   const CPPType *type_;
 | |
|   int64_t size_;
 | |
| 
 | |
|  public:
 | |
|   GVArray(const CPPType &type, const int64_t size) : type_(&type), size_(size)
 | |
|   {
 | |
|     BLI_assert(size_ >= 0);
 | |
|   }
 | |
| 
 | |
|   virtual ~GVArray() = default;
 | |
| 
 | |
|   const CPPType &type() const
 | |
|   {
 | |
|     return *type_;
 | |
|   }
 | |
| 
 | |
|   int64_t size() const
 | |
|   {
 | |
|     return size_;
 | |
|   }
 | |
| 
 | |
|   bool is_empty() const
 | |
|   {
 | |
|     return size_;
 | |
|   }
 | |
| 
 | |
|   /* Copies the value at the given index into the provided storage. The `r_value` pointer is
 | |
|    * expected to point to initialized memory. */
 | |
|   void get(const int64_t index, void *r_value) const
 | |
|   {
 | |
|     BLI_assert(index >= 0);
 | |
|     BLI_assert(index < size_);
 | |
|     this->get_impl(index, r_value);
 | |
|   }
 | |
| 
 | |
|   /* Same as `get`, but `r_value` is expected to point to uninitialized memory. */
 | |
|   void get_to_uninitialized(const int64_t index, void *r_value) const
 | |
|   {
 | |
|     BLI_assert(index >= 0);
 | |
|     BLI_assert(index < size_);
 | |
|     this->get_to_uninitialized_impl(index, r_value);
 | |
|   }
 | |
| 
 | |
|   /* Returns true when the virtual array is stored as a span internally. */
 | |
|   bool is_span() const
 | |
|   {
 | |
|     if (size_ == 0) {
 | |
|       return true;
 | |
|     }
 | |
|     return this->is_span_impl();
 | |
|   }
 | |
| 
 | |
|   /* Returns the internally used span of the virtual array. This invokes undefined behavior is the
 | |
|    * virtual array is not stored as a span internally. */
 | |
|   GSpan get_internal_span() const
 | |
|   {
 | |
|     BLI_assert(this->is_span());
 | |
|     if (size_ == 0) {
 | |
|       return GSpan(*type_);
 | |
|     }
 | |
|     return this->get_internal_span_impl();
 | |
|   }
 | |
| 
 | |
|   /* Returns true when the virtual array returns the same value for every index. */
 | |
|   bool is_single() const
 | |
|   {
 | |
|     if (size_ == 1) {
 | |
|       return true;
 | |
|     }
 | |
|     return this->is_single_impl();
 | |
|   }
 | |
| 
 | |
|   /* Copies the value that is used for every element into `r_value`, which is expected to point to
 | |
|    * initialized memory. This invokes undefined behavior if the virtual array would not return the
 | |
|    * same value for every index. */
 | |
|   void get_internal_single(void *r_value) const
 | |
|   {
 | |
|     BLI_assert(this->is_single());
 | |
|     if (size_ == 1) {
 | |
|       this->get(0, r_value);
 | |
|     }
 | |
|     this->get_internal_single_impl(r_value);
 | |
|   }
 | |
| 
 | |
|   /* Same as `get_internal_single`, but `r_value` points to initialized memory. */
 | |
|   void get_single_to_uninitialized(void *r_value) const
 | |
|   {
 | |
|     type_->construct_default(r_value);
 | |
|     this->get_internal_single(r_value);
 | |
|   }
 | |
| 
 | |
|   void materialize_to_uninitialized(void *dst) const;
 | |
|   void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
 | |
| 
 | |
|   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);
 | |
|   }
 | |
| 
 | |
|   GVArrayPtr shallow_copy() const;
 | |
| 
 | |
|  protected:
 | |
|   virtual void get_impl(const int64_t index, void *r_value) const;
 | |
|   virtual void get_to_uninitialized_impl(const int64_t index, void *r_value) const = 0;
 | |
| 
 | |
|   virtual bool is_span_impl() const;
 | |
|   virtual GSpan get_internal_span_impl() const;
 | |
| 
 | |
|   virtual bool is_single_impl() const;
 | |
|   virtual void get_internal_single_impl(void *UNUSED(r_value)) const;
 | |
| 
 | |
|   virtual void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const;
 | |
| 
 | |
|   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);
 | |
| 
 | |
|  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;
 | |
| 
 | |
|   virtual void *try_get_internal_mutable_varray_impl();
 | |
| };
 | |
| 
 | |
| class GVArray_For_GSpan : public GVArray {
 | |
|  protected:
 | |
|   const void *data_ = nullptr;
 | |
|   const int64_t element_size_;
 | |
| 
 | |
|  public:
 | |
|   GVArray_For_GSpan(const GSpan span)
 | |
|       : GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size())
 | |
|   {
 | |
|   }
 | |
| 
 | |
|  protected:
 | |
|   GVArray_For_GSpan(const CPPType &type, const int64_t size)
 | |
|       : GVArray(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;
 | |
| 
 | |
|   bool is_span_impl() const override;
 | |
|   GSpan get_internal_span_impl() const override;
 | |
| };
 | |
| 
 | |
| class GVArray_For_Empty : public GVArray {
 | |
|  public:
 | |
|   GVArray_For_Empty(const CPPType &type) : GVArray(type, 0)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|  protected:
 | |
|   void get_to_uninitialized_impl(const int64_t UNUSED(index), void *UNUSED(r_value)) const override
 | |
|   {
 | |
|     BLI_assert(false);
 | |
|   }
 | |
| };
 | |
| 
 | |
| class 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;
 | |
| 
 | |
|  public:
 | |
|   GVArray_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
 | |
|       : GVArray(type, size), value_(value)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|  protected:
 | |
|   GVArray_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArray(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;
 | |
| 
 | |
|   bool is_span_impl() const override;
 | |
|   GSpan get_internal_span_impl() const override;
 | |
| 
 | |
|   bool is_single_impl() const override;
 | |
|   void get_internal_single_impl(void *r_value) const override;
 | |
| };
 | |
| 
 | |
| /* 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;
 | |
| 
 | |
|  public:
 | |
|   GVArray_For_VArray(const VArray<T> &varray)
 | |
|       : GVArray(CPPType::get<T>(), varray.size()), varray_(&varray)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|  protected:
 | |
|   GVArray_For_VArray(const int64_t size) : GVArray(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
 | |
|   {
 | |
|     return GSpan(varray_->get_internal_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 materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override
 | |
|   {
 | |
|     varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
 | |
|   }
 | |
| 
 | |
|   const void *try_get_internal_varray_impl() const override
 | |
|   {
 | |
|     return varray_;
 | |
|   }
 | |
| };
 | |
| 
 | |
| /* 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;
 | |
| 
 | |
|  public:
 | |
|   VArray_For_GVArray(const GVArray &varray) : VArray<T>(varray.size()), varray_(&varray)
 | |
|   {
 | |
|     BLI_assert(varray_->type().template is<T>());
 | |
|   }
 | |
| 
 | |
|  protected:
 | |
|   VArray_For_GVArray(const int64_t size) : VArray<T>(size)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   T get_impl(const int64_t index) const override
 | |
|   {
 | |
|     T value;
 | |
|     varray_->get(index, &value);
 | |
|     return 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 an generic mutable virtual array into a typed one. */
 | |
| template<typename T> class VMutableArray_For_GVMutableArray : public VMutableArray<T> {
 | |
|  protected:
 | |
|   GVMutableArray *varray_ = nullptr;
 | |
| 
 | |
|  public:
 | |
|   VMutableArray_For_GVMutableArray(GVMutableArray &varray)
 | |
|       : VMutableArray<T>(varray.size()), varray_(&varray)
 | |
|   {
 | |
|     BLI_assert(varray.type().template is<T>());
 | |
|   }
 | |
| 
 | |
|   VMutableArray_For_GVMutableArray(const int64_t size) : VMutableArray<T>(size)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   T get_impl(const int64_t index) const override
 | |
|   {
 | |
|     T value;
 | |
|     varray_->get(index, &value);
 | |
|     return value;
 | |
|   }
 | |
| 
 | |
|   void set_impl(const int64_t index, T value) override
 | |
|   {
 | |
|     varray_->set_by_relocate(index, &value);
 | |
|   }
 | |
| 
 | |
|   bool is_span_impl() const override
 | |
|   {
 | |
|     return varray_->is_span();
 | |
|   }
 | |
| 
 | |
|   Span<T> get_internal_span_impl() const override
 | |
|   {
 | |
|     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_));
 | |
|   }
 | |
| 
 | |
|   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:
 | |
|   VArrayPtr<T> owned_varray_;
 | |
| 
 | |
|  public:
 | |
|   /* Takes ownership of varray and passes a reference to the base class. */
 | |
|   GVArray_For_OwnedVArray(VArrayPtr<T> varray)
 | |
|       : GVArray_For_VArray<T>(*varray), owned_varray_(std::move(varray))
 | |
|   {
 | |
|   }
 | |
| };
 | |
| 
 | |
| template<typename T> class VArray_For_OwnedGVArray : public VArray_For_GVArray<T> {
 | |
|  private:
 | |
|   GVArrayPtr owned_varray_;
 | |
| 
 | |
|  public:
 | |
|   /* Takes ownership of varray and passes a reference to the base class. */
 | |
|   VArray_For_OwnedGVArray(GVArrayPtr varray)
 | |
|       : VArray_For_GVArray<T>(*varray), owned_varray_(std::move(varray))
 | |
|   {
 | |
|   }
 | |
| };
 | |
| 
 | |
| template<typename T>
 | |
| class GVMutableArray_For_OwnedVMutableArray : public GVMutableArray_For_VMutableArray<T> {
 | |
|  private:
 | |
|   VMutableArrayPtr<T> owned_varray_;
 | |
| 
 | |
|  public:
 | |
|   /* Takes ownership of varray and passes a reference to the base class. */
 | |
|   GVMutableArray_For_OwnedVMutableArray(VMutableArrayPtr<T> varray)
 | |
|       : GVMutableArray_For_VMutableArray<T>(*varray), owned_varray_(std::move(varray))
 | |
|   {
 | |
|   }
 | |
| };
 | |
| 
 | |
| template<typename T>
 | |
| class VMutableArray_For_OwnedGVMutableArray : public VMutableArray_For_GVMutableArray<T> {
 | |
|  private:
 | |
|   GVMutableArrayPtr owned_varray_;
 | |
| 
 | |
|  public:
 | |
|   /* Takes ownership of varray and passes a reference to the base class. */
 | |
|   VMutableArray_For_OwnedGVMutableArray(GVMutableArrayPtr varray)
 | |
|       : VMutableArray_For_GVMutableArray<T>(*varray), owned_varray_(std::move(varray))
 | |
|   {
 | |
|   }
 | |
| };
 | |
| 
 | |
| /* Utility to embed a typed virtual array into a generic one. This avoids one allocation and give
 | |
|  * the compiler more opportunity to optimize the generic virtual array. */
 | |
| template<typename T, typename VArrayT>
 | |
| class GVArray_For_EmbeddedVArray : public GVArray_For_VArray<T> {
 | |
|  private:
 | |
|   VArrayT embedded_varray_;
 | |
| 
 | |
|  public:
 | |
|   template<typename... Args>
 | |
|   GVArray_For_EmbeddedVArray(const int64_t size, Args &&... args)
 | |
|       : GVArray_For_VArray<T>(size), embedded_varray_(std::forward<Args>(args)...)
 | |
|   {
 | |
|     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>
 | |
|   GVMutableArray_For_EmbeddedVMutableArray(const int64_t size, Args &&... args)
 | |
|       : 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_;
 | |
|   GVArrayPtr owned_gvarray_;
 | |
| 
 | |
|  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. */
 | |
|   explicit GVArray_Typed(GVArrayPtr gvarray) : GVArray_Typed(*gvarray)
 | |
|   {
 | |
|     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
 | |
|    * used within an expression.  */
 | |
|   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_;
 | |
|   GVMutableArrayPtr owned_gvarray_;
 | |
| 
 | |
|  public:
 | |
|   explicit GVMutableArray_Typed(GVMutableArray &gvarray)
 | |
|   {
 | |
|     BLI_assert(gvarray.type().is<T>());
 | |
|     if (gvarray.is_span()) {
 | |
|       const GMutableSpan span = gvarray.get_internal_span();
 | |
|       varray_span_.emplace(span.typed<T>());
 | |
|       varray_ = &*varray_span_;
 | |
|     }
 | |
|     else if (VMutableArray<T> *internal_varray = gvarray.try_get_internal_mutable_varray<T>()) {
 | |
|       varray_ = internal_varray;
 | |
|     }
 | |
|     else {
 | |
|       varray_any_.emplace(gvarray);
 | |
|       varray_ = &*varray_any_;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   explicit GVMutableArray_Typed(GVMutableArrayPtr gvarray) : GVMutableArray_Typed(*gvarray)
 | |
|   {
 | |
|     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();
 | |
|   }
 | |
| };
 | |
| 
 | |
| }  // namespace blender::fn
 |