tornavis/source/blender/blenlib/BLI_generic_virtual_array.hh

970 lines
28 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup bli
*
* A generic virtual array is the same as a virtual array, except for the fact that the data type
* is only known at runtime.
*/
#include "BLI_generic_array.hh"
#include "BLI_generic_span.hh"
#include "BLI_timeit.hh"
#include "BLI_virtual_array.hh"
namespace blender {
/* -------------------------------------------------------------------- */
/** \name #GVArrayImpl and #GVMutableArrayImpl.
* \{ */
class GVArray;
class GVArrayImpl;
class GVMutableArray;
class GVMutableArrayImpl;
/* A generically typed version of #VArrayImpl. */
class GVArrayImpl {
protected:
const CPPType *type_;
int64_t size_;
public:
GVArrayImpl(const CPPType &type, int64_t size);
virtual ~GVArrayImpl() = default;
const CPPType &type() const;
int64_t size() const;
virtual void get(int64_t index, void *r_value) const;
virtual void get_to_uninitialized(int64_t index, void *r_value) const = 0;
virtual CommonVArrayInfo common_info() const;
virtual void materialize(const IndexMask &mask, void *dst) const;
virtual void materialize_to_uninitialized(const IndexMask &mask, void *dst) const;
virtual void materialize_compressed(const IndexMask &mask, void *dst) const;
virtual void materialize_compressed_to_uninitialized(const IndexMask &mask, void *dst) const;
virtual bool try_assign_VArray(void *varray) const;
};
/* A generic version of #VMutableArrayImpl. */
class GVMutableArrayImpl : public GVArrayImpl {
public:
GVMutableArrayImpl(const CPPType &type, int64_t size) : GVArrayImpl(type, size) {}
virtual void set_by_copy(int64_t index, const void *value);
virtual void set_by_relocate(int64_t index, void *value);
virtual void set_by_move(int64_t index, void *value) = 0;
virtual void set_all(const void *src);
virtual bool try_assign_VMutableArray(void *varray) const;
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name #GVArray and #GVMutableArray
* \{ */
namespace detail {
struct GVArrayAnyExtraInfo {
const GVArrayImpl *(*get_varray)(const void *buffer) =
[](const void * /*buffer*/) -> const GVArrayImpl * { return nullptr; };
template<typename StorageT> static constexpr GVArrayAnyExtraInfo get();
};
} // namespace detail
class GVMutableArray;
/**
* Utility class to reduce code duplication between #GVArray and #GVMutableArray.
* It pretty much follows #VArrayCommon. Don't use this class outside of this header.
*/
class GVArrayCommon {
protected:
/**
* See #VArrayCommon for more information. The inline buffer is a bit larger here, because
* generic virtual array implementations often require a bit more space than typed ones.
*/
using Storage = Any<detail::GVArrayAnyExtraInfo, 40, 8>;
const GVArrayImpl *impl_ = nullptr;
Storage storage_;
protected:
GVArrayCommon() = default;
GVArrayCommon(const GVArrayCommon &other);
GVArrayCommon(GVArrayCommon &&other) noexcept;
GVArrayCommon(const GVArrayImpl *impl);
GVArrayCommon(std::shared_ptr<const GVArrayImpl> impl);
~GVArrayCommon();
template<typename ImplT, typename... Args> void emplace(Args &&...args);
void copy_from(const GVArrayCommon &other);
void move_from(GVArrayCommon &&other) noexcept;
const GVArrayImpl *impl_from_storage() const;
public:
const CPPType &type() const;
operator bool() const;
int64_t size() const;
bool is_empty() const;
IndexRange index_range() const;
template<typename T> bool try_assign_VArray(VArray<T> &varray) const;
bool may_have_ownership() const;
void materialize(void *dst) const;
void materialize(const IndexMask &mask, void *dst) const;
void materialize_to_uninitialized(void *dst) const;
void materialize_to_uninitialized(const IndexMask &mask, void *dst) const;
void materialize_compressed(const IndexMask &mask, void *dst) const;
void materialize_compressed_to_uninitialized(const IndexMask &mask, void *dst) const;
CommonVArrayInfo common_info() const;
/**
* Returns true when the virtual array is stored as a span internally.
*/
bool is_span() const;
/**
* Returns the internally used span of the virtual array. This invokes undefined behavior if the
* virtual array is not stored as a span internally.
*/
GSpan get_internal_span() const;
/**
* Returns true when the virtual array returns the same value for every index.
*/
bool is_single() const;
/**
* 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;
/**
* Same as `get_internal_single`, but `r_value` points to initialized memory.
*/
void get_internal_single_to_uninitialized(void *r_value) const;
void get(int64_t index, void *r_value) const;
/**
* Returns a copy of the value at the given index. Usually a typed virtual array should
* be used instead, but sometimes this is simpler when only a few indices are needed.
*/
template<typename T> T get(int64_t index) const;
void get_to_uninitialized(int64_t index, void *r_value) const;
};
/** Generic version of #VArray. */
class GVArray : public GVArrayCommon {
private:
friend GVMutableArray;
public:
GVArray() = default;
GVArray(const GVArray &other);
GVArray(GVArray &&other) noexcept;
GVArray(const GVArrayImpl *impl);
GVArray(std::shared_ptr<const GVArrayImpl> impl);
GVArray(varray_tag::span /*tag*/, GSpan span);
GVArray(varray_tag::single_ref /*tag*/, const CPPType &type, int64_t size, const void *value);
GVArray(varray_tag::single /*tag*/, const CPPType &type, int64_t size, const void *value);
template<typename T> GVArray(const VArray<T> &varray);
template<typename T> VArray<T> typed() const;
template<typename ImplT, typename... Args> static GVArray For(Args &&...args);
static GVArray ForSingle(const CPPType &type, int64_t size, const void *value);
static GVArray ForSingleRef(const CPPType &type, int64_t size, const void *value);
static GVArray ForSingleDefault(const CPPType &type, int64_t size);
static GVArray ForSpan(GSpan span);
static GVArray ForGArray(GArray<> array);
static GVArray ForEmpty(const CPPType &type);
GVArray slice(IndexRange slice) const;
GVArray &operator=(const GVArray &other);
GVArray &operator=(GVArray &&other) noexcept;
const GVArrayImpl *get_implementation() const
{
return impl_;
}
};
/** Generic version of #VMutableArray. */
class GVMutableArray : public GVArrayCommon {
public:
GVMutableArray() = default;
GVMutableArray(const GVMutableArray &other);
GVMutableArray(GVMutableArray &&other) noexcept;
GVMutableArray(GVMutableArrayImpl *impl);
GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl);
template<typename T> GVMutableArray(const VMutableArray<T> &varray);
template<typename T> VMutableArray<T> typed() const;
template<typename ImplT, typename... Args> static GVMutableArray For(Args &&...args);
static GVMutableArray ForSpan(GMutableSpan span);
operator GVArray() const &;
operator GVArray() && noexcept;
GVMutableArray &operator=(const GVMutableArray &other);
GVMutableArray &operator=(GVMutableArray &&other) noexcept;
GMutableSpan get_internal_span() const;
template<typename T> bool try_assign_VMutableArray(VMutableArray<T> &varray) const;
void set_by_copy(int64_t index, const void *value);
void set_by_move(int64_t index, void *value);
void set_by_relocate(int64_t index, void *value);
void fill(const void *value);
/**
* Copy the values from the source buffer to all elements in the virtual array.
*/
void set_all(const void *src);
GVMutableArrayImpl *get_implementation() const;
private:
GVMutableArrayImpl *get_impl() const;
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name #GVArraySpan and #GMutableVArraySpan.
* \{ */
/* A generic version of VArraySpan. */
class GVArraySpan : public GSpan {
private:
GVArray varray_;
void *owned_data_ = nullptr;
public:
GVArraySpan();
GVArraySpan(GVArray varray);
GVArraySpan(GVArraySpan &&other);
~GVArraySpan();
GVArraySpan &operator=(GVArraySpan &&other);
};
/* A generic version of MutableVArraySpan. */
class GMutableVArraySpan : public GMutableSpan, NonCopyable, NonMovable {
private:
GVMutableArray varray_;
void *owned_data_ = nullptr;
bool save_has_been_called_ = false;
bool show_not_saved_warning_ = true;
public:
GMutableVArraySpan();
GMutableVArraySpan(GVMutableArray varray, bool copy_values_to_span = true);
GMutableVArraySpan(GMutableVArraySpan &&other);
~GMutableVArraySpan();
GMutableVArraySpan &operator=(GMutableVArraySpan &&other);
const GVMutableArray &varray() const;
void save();
void disable_not_applied_warning();
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name Conversions between generic and typed virtual arrays.
* \{ */
/* Used to convert a typed virtual array into a generic one. */
template<typename T> class GVArrayImpl_For_VArray : public GVArrayImpl {
protected:
VArray<T> varray_;
public:
GVArrayImpl_For_VArray(VArray<T> varray)
: GVArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray))
{
}
protected:
void get(const int64_t index, void *r_value) const override
{
*static_cast<T *>(r_value) = varray_[index];
}
void get_to_uninitialized(const int64_t index, void *r_value) const override
{
new (r_value) T(varray_[index]);
}
void materialize(const IndexMask &mask, void *dst) const override
{
varray_.materialize(mask, MutableSpan(static_cast<T *>(dst), mask.min_array_size()));
}
void materialize_to_uninitialized(const IndexMask &mask, void *dst) const override
{
varray_.materialize_to_uninitialized(
mask, MutableSpan(static_cast<T *>(dst), mask.min_array_size()));
}
void materialize_compressed(const IndexMask &mask, void *dst) const override
{
varray_.materialize_compressed(mask, MutableSpan(static_cast<T *>(dst), mask.size()));
}
void materialize_compressed_to_uninitialized(const IndexMask &mask, void *dst) const override
{
varray_.materialize_compressed_to_uninitialized(
mask, MutableSpan(static_cast<T *>(dst), mask.size()));
}
bool try_assign_VArray(void *varray) const override
{
*(VArray<T> *)varray = varray_;
return true;
}
CommonVArrayInfo common_info() const override
{
return varray_.common_info();
}
};
/* Used to convert any generic virtual array into a typed one. */
template<typename T> class VArrayImpl_For_GVArray : public VArrayImpl<T> {
protected:
GVArray varray_;
public:
VArrayImpl_For_GVArray(GVArray varray) : VArrayImpl<T>(varray.size()), varray_(std::move(varray))
{
BLI_assert(varray_);
BLI_assert(varray_.type().template is<T>());
}
protected:
T get(const int64_t index) const override
{
T value;
varray_.get(index, &value);
return value;
}
CommonVArrayInfo common_info() const override
{
return varray_.common_info();
}
bool try_assign_GVArray(GVArray &varray) const override
{
varray = varray_;
return true;
}
void materialize(const IndexMask &mask, T *dst) const override
{
varray_.materialize(mask, dst);
}
void materialize_to_uninitialized(const IndexMask &mask, T *dst) const override
{
varray_.materialize_to_uninitialized(mask, dst);
}
void materialize_compressed(const IndexMask &mask, T *dst) const override
{
varray_.materialize_compressed(mask, dst);
}
void materialize_compressed_to_uninitialized(const IndexMask &mask, T *dst) const override
{
varray_.materialize_compressed_to_uninitialized(mask, dst);
}
};
/* Used to convert any typed virtual mutable array into a generic one. */
template<typename T> class GVMutableArrayImpl_For_VMutableArray : public GVMutableArrayImpl {
protected:
VMutableArray<T> varray_;
public:
GVMutableArrayImpl_For_VMutableArray(VMutableArray<T> varray)
: GVMutableArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray))
{
}
protected:
void get(const int64_t index, void *r_value) const override
{
*static_cast<T *>(r_value) = varray_[index];
}
void get_to_uninitialized(const int64_t index, void *r_value) const override
{
new (r_value) T(varray_[index]);
}
CommonVArrayInfo common_info() const override
{
return varray_.common_info();
}
void set_by_copy(const int64_t index, const void *value) override
{
const T &value_ = *(const T *)value;
varray_.set(index, value_);
}
void set_by_relocate(const int64_t index, void *value) override
{
T &value_ = *static_cast<T *>(value);
varray_.set(index, std::move(value_));
value_.~T();
}
void set_by_move(const int64_t index, void *value) override
{
T &value_ = *static_cast<T *>(value);
varray_.set(index, std::move(value_));
}
void set_all(const void *src) override
{
varray_.set_all(Span(static_cast<const T *>(src), size_));
}
void materialize(const IndexMask &mask, void *dst) const override
{
varray_.materialize(mask, MutableSpan(static_cast<T *>(dst), mask.min_array_size()));
}
void materialize_to_uninitialized(const IndexMask &mask, void *dst) const override
{
varray_.materialize_to_uninitialized(
mask, MutableSpan(static_cast<T *>(dst), mask.min_array_size()));
}
void materialize_compressed(const IndexMask &mask, void *dst) const override
{
varray_.materialize_compressed(mask, MutableSpan(static_cast<T *>(dst), mask.size()));
}
void materialize_compressed_to_uninitialized(const IndexMask &mask, void *dst) const override
{
varray_.materialize_compressed_to_uninitialized(
mask, MutableSpan(static_cast<T *>(dst), mask.size()));
}
bool try_assign_VArray(void *varray) const override
{
*(VArray<T> *)varray = varray_;
return true;
}
bool try_assign_VMutableArray(void *varray) const override
{
*(VMutableArray<T> *)varray = varray_;
return true;
}
};
/* Used to convert an generic mutable virtual array into a typed one. */
template<typename T> class VMutableArrayImpl_For_GVMutableArray : public VMutableArrayImpl<T> {
protected:
GVMutableArray varray_;
public:
VMutableArrayImpl_For_GVMutableArray(GVMutableArray varray)
: VMutableArrayImpl<T>(varray.size()), varray_(varray)
{
BLI_assert(varray_);
BLI_assert(varray_.type().template is<T>());
}
private:
T get(const int64_t index) const override
{
T value;
varray_.get(index, &value);
return value;
}
void set(const int64_t index, T value) override
{
varray_.set_by_relocate(index, &value);
}
CommonVArrayInfo common_info() const override
{
return varray_.common_info();
}
bool try_assign_GVArray(GVArray &varray) const override
{
varray = varray_;
return true;
}
bool try_assign_GVMutableArray(GVMutableArray &varray) const override
{
varray = varray_;
return true;
}
void materialize(const IndexMask &mask, T *dst) const override
{
varray_.materialize(mask, dst);
}
void materialize_to_uninitialized(const IndexMask &mask, T *dst) const override
{
varray_.materialize_to_uninitialized(mask, dst);
}
void materialize_compressed(const IndexMask &mask, T *dst) const override
{
varray_.materialize_compressed(mask, dst);
}
void materialize_compressed_to_uninitialized(const IndexMask &mask, T *dst) const override
{
varray_.materialize_compressed_to_uninitialized(mask, dst);
}
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name #GVArrayImpl_For_GSpan.
* \{ */
class GVArrayImpl_For_GSpan : public GVMutableArrayImpl {
protected:
void *data_ = nullptr;
const int64_t element_size_;
public:
GVArrayImpl_For_GSpan(const GMutableSpan span)
: GVMutableArrayImpl(span.type(), span.size()),
data_(span.data()),
element_size_(span.type().size())
{
}
protected:
GVArrayImpl_For_GSpan(const CPPType &type, int64_t size)
: GVMutableArrayImpl(type, size), element_size_(type.size())
{
}
public:
void get(int64_t index, void *r_value) const override;
void get_to_uninitialized(int64_t index, void *r_value) const override;
void set_by_copy(int64_t index, const void *value) override;
void set_by_move(int64_t index, void *value) override;
void set_by_relocate(int64_t index, void *value) override;
CommonVArrayInfo common_info() const override;
virtual void materialize(const IndexMask &mask, void *dst) const override;
virtual void materialize_to_uninitialized(const IndexMask &mask, void *dst) const override;
virtual void materialize_compressed(const IndexMask &mask, void *dst) const override;
virtual void materialize_compressed_to_uninitialized(const IndexMask &mask,
void *dst) const override;
};
class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
public:
using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan;
private:
CommonVArrayInfo common_info() const override;
};
template<> inline constexpr bool is_trivial_extended_v<GVArrayImpl_For_GSpan_final> = true;
/** \} */
/* -------------------------------------------------------------------- */
/** \name #GVArrayImpl_For_SingleValueRef.
* \{ */
class GVArrayImpl_For_SingleValueRef : public GVArrayImpl {
protected:
const void *value_ = nullptr;
public:
GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
: GVArrayImpl(type, size), value_(value)
{
}
protected:
GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArrayImpl(type, size)
{
}
void get(const int64_t index, void *r_value) const override;
void get_to_uninitialized(const int64_t index, void *r_value) const override;
CommonVArrayInfo common_info() const override;
void materialize(const IndexMask &mask, void *dst) const override;
void materialize_to_uninitialized(const IndexMask &mask, void *dst) const override;
void materialize_compressed(const IndexMask &mask, void *dst) const override;
void materialize_compressed_to_uninitialized(const IndexMask &mask, void *dst) const override;
};
class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_SingleValueRef {
public:
using GVArrayImpl_For_SingleValueRef::GVArrayImpl_For_SingleValueRef;
private:
CommonVArrayInfo common_info() const override;
};
template<>
inline constexpr bool is_trivial_extended_v<GVArrayImpl_For_SingleValueRef_final> = true;
/** \} */
/* -------------------------------------------------------------------- */
/** \name Inline methods for #GVArrayImpl.
* \{ */
inline GVArrayImpl::GVArrayImpl(const CPPType &type, const int64_t size)
: type_(&type), size_(size)
{
BLI_assert(size_ >= 0);
}
inline const CPPType &GVArrayImpl::type() const
{
return *type_;
}
inline int64_t GVArrayImpl::size() const
{
return size_;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Inline methods for #GVMutableArrayImpl.
* \{ */
inline void GVMutableArray::set_by_copy(const int64_t index, const void *value)
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
this->get_impl()->set_by_copy(index, value);
}
inline void GVMutableArray::set_by_move(const int64_t index, void *value)
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
this->get_impl()->set_by_move(index, value);
}
inline void GVMutableArray::set_by_relocate(const int64_t index, void *value)
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
this->get_impl()->set_by_relocate(index, value);
}
template<typename T>
inline bool GVMutableArray::try_assign_VMutableArray(VMutableArray<T> &varray) const
{
BLI_assert(impl_->type().is<T>());
return this->get_impl()->try_assign_VMutableArray(&varray);
}
inline GVMutableArrayImpl *GVMutableArray::get_impl() const
{
return const_cast<GVMutableArrayImpl *>(static_cast<const GVMutableArrayImpl *>(impl_));
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Inline methods for #GVArrayCommon.
* \{ */
template<typename ImplT, typename... Args> inline void GVArrayCommon::emplace(Args &&...args)
{
static_assert(std::is_base_of_v<GVArrayImpl, ImplT>);
if constexpr (std::is_copy_constructible_v<ImplT> && Storage::template is_inline_v<ImplT>) {
impl_ = &storage_.template emplace<ImplT>(std::forward<Args>(args)...);
}
else {
std::shared_ptr<const GVArrayImpl> ptr = std::make_shared<ImplT>(std::forward<Args>(args)...);
impl_ = &*ptr;
storage_ = std::move(ptr);
}
}
/* Copies the value at the given index into the provided storage. The `r_value` pointer is
* expected to point to initialized memory. */
inline void GVArrayCommon::get(const int64_t index, void *r_value) const
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
impl_->get(index, r_value);
}
template<typename T> inline T GVArrayCommon::get(const int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
BLI_assert(this->type().is<T>());
T value{};
impl_->get(index, &value);
return value;
}
/* Same as `get`, but `r_value` is expected to point to uninitialized memory. */
inline void GVArrayCommon::get_to_uninitialized(const int64_t index, void *r_value) const
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
impl_->get_to_uninitialized(index, r_value);
}
template<typename T> inline bool GVArrayCommon::try_assign_VArray(VArray<T> &varray) const
{
BLI_assert(impl_->type().is<T>());
return impl_->try_assign_VArray(&varray);
}
inline const CPPType &GVArrayCommon::type() const
{
return impl_->type();
}
inline GVArrayCommon::operator bool() const
{
return impl_ != nullptr;
}
inline CommonVArrayInfo GVArrayCommon::common_info() const
{
return impl_->common_info();
}
inline int64_t GVArrayCommon::size() const
{
if (impl_ == nullptr) {
return 0;
}
return impl_->size();
}
inline bool GVArrayCommon::is_empty() const
{
return this->size() == 0;
}
/** \} */
/** To be used with #call_with_devirtualized_parameters. */
template<typename T, bool UseSingle, bool UseSpan> struct GVArrayDevirtualizer {
const GVArrayImpl &varray_impl;
template<typename Fn> bool devirtualize(const Fn &fn) const
{
const CommonVArrayInfo info = this->varray_impl.common_info();
const int64_t size = this->varray_impl.size();
if constexpr (UseSingle) {
if (info.type == CommonVArrayInfo::Type::Single) {
return fn(SingleAsSpan<T>(*static_cast<const T *>(info.data), size));
}
}
if constexpr (UseSpan) {
if (info.type == CommonVArrayInfo::Type::Span) {
return fn(Span<T>(static_cast<const T *>(info.data), size));
}
}
return false;
}
};
/* -------------------------------------------------------------------- */
/** \name Inline methods for #GVArray.
* \{ */
inline GVArray::GVArray(varray_tag::span /*tag*/, const GSpan span)
{
/* Use const-cast because the underlying virtual array implementation is shared between const
* and non const data. */
GMutableSpan mutable_span{span.type(), const_cast<void *>(span.data()), span.size()};
this->emplace<GVArrayImpl_For_GSpan_final>(mutable_span);
}
inline GVArray::GVArray(varray_tag::single_ref /*tag*/,
const CPPType &type,
const int64_t size,
const void *value)
{
this->emplace<GVArrayImpl_For_SingleValueRef_final>(type, size, value);
}
namespace detail {
template<typename StorageT> constexpr GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get()
{
static_assert(std::is_base_of_v<GVArrayImpl, StorageT> ||
is_same_any_v<StorageT, const GVArrayImpl *, std::shared_ptr<const GVArrayImpl>>);
if constexpr (std::is_base_of_v<GVArrayImpl, StorageT>) {
return {[](const void *buffer) {
return static_cast<const GVArrayImpl *>((const StorageT *)buffer);
}};
}
else if constexpr (std::is_same_v<StorageT, const GVArrayImpl *>) {
return {[](const void *buffer) { return *(const StorageT *)buffer; }};
}
else if constexpr (std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>) {
return {[](const void *buffer) { return ((const StorageT *)buffer)->get(); }};
}
else {
BLI_assert_unreachable();
return {};
}
}
} // namespace detail
template<typename ImplT, typename... Args> inline GVArray GVArray::For(Args &&...args)
{
static_assert(std::is_base_of_v<GVArrayImpl, ImplT>);
GVArray varray;
varray.template emplace<ImplT>(std::forward<Args>(args)...);
return varray;
}
template<typename T> inline GVArray::GVArray(const VArray<T> &varray)
{
if (!varray) {
return;
}
const CommonVArrayInfo info = varray.common_info();
if (info.type == CommonVArrayInfo::Type::Single) {
*this = GVArray::ForSingle(CPPType::get<T>(), varray.size(), info.data);
return;
}
/* Need to check for ownership, because otherwise the referenced data can be destructed when
* #this is destructed. */
if (info.type == CommonVArrayInfo::Type::Span && !info.may_have_ownership) {
*this = GVArray::ForSpan(GSpan(CPPType::get<T>(), info.data, varray.size()));
return;
}
if (varray.try_assign_GVArray(*this)) {
return;
}
*this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
}
template<typename T> inline VArray<T> GVArray::typed() const
{
if (!*this) {
return {};
}
BLI_assert(impl_->type().is<T>());
const CommonVArrayInfo info = this->common_info();
if (info.type == CommonVArrayInfo::Type::Single) {
return VArray<T>::ForSingle(*static_cast<const T *>(info.data), this->size());
}
/* Need to check for ownership, because otherwise the referenced data can be destructed when
* #this is destructed. */
if (info.type == CommonVArrayInfo::Type::Span && !info.may_have_ownership) {
return VArray<T>::ForSpan(Span<T>(static_cast<const T *>(info.data), this->size()));
}
VArray<T> varray;
if (this->try_assign_VArray(varray)) {
return varray;
}
return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Inline methods for #GVMutableArray.
* \{ */
template<typename ImplT, typename... Args>
inline GVMutableArray GVMutableArray::For(Args &&...args)
{
static_assert(std::is_base_of_v<GVMutableArrayImpl, ImplT>);
GVMutableArray varray;
varray.emplace<ImplT>(std::forward<Args>(args)...);
return varray;
}
template<typename T> inline GVMutableArray::GVMutableArray(const VMutableArray<T> &varray)
{
if (!varray) {
return;
}
const CommonVArrayInfo info = varray.common_info();
if (info.type == CommonVArrayInfo::Type::Span && !info.may_have_ownership) {
*this = GVMutableArray::ForSpan(
GMutableSpan(CPPType::get<T>(), const_cast<void *>(info.data), varray.size()));
return;
}
if (varray.try_assign_GVMutableArray(*this)) {
return;
}
*this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray);
}
template<typename T> inline VMutableArray<T> GVMutableArray::typed() const
{
if (!*this) {
return {};
}
BLI_assert(this->type().is<T>());
const CommonVArrayInfo info = this->common_info();
if (info.type == CommonVArrayInfo::Type::Span && !info.may_have_ownership) {
return VMutableArray<T>::ForSpan(
MutableSpan<T>(const_cast<T *>(static_cast<const T *>(info.data)), this->size()));
}
VMutableArray<T> varray;
if (this->try_assign_VMutableArray(varray)) {
return varray;
}
return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this);
}
/** \} */
} // namespace blender