970 lines
28 KiB
C++
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
|