BLI: optimize constructing new virtual array
Differential Revision: https://developer.blender.org/D14745
This commit is contained in:
parent
c63d64a2ce
commit
a2d32960b4
|
@ -31,55 +31,37 @@ template<typename ExtraInfo> struct AnyTypeInfo {
|
|||
void (*destruct)(void *src);
|
||||
const void *(*get)(const void *src);
|
||||
ExtraInfo extra_info;
|
||||
|
||||
/**
|
||||
* Used when #T is stored directly in the inline buffer of the #Any.
|
||||
*/
|
||||
template<typename T> static const AnyTypeInfo &get_for_inline()
|
||||
{
|
||||
static AnyTypeInfo funcs = {[](void *dst, const void *src) { new (dst) T(*(const T *)src); },
|
||||
[](void *dst, void *src) { new (dst) T(std::move(*(T *)src)); },
|
||||
[](void *src) { ((T *)src)->~T(); },
|
||||
[](const void *src) { return src; },
|
||||
ExtraInfo::template get<T>()};
|
||||
return funcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when #T can't be stored directly in the inline buffer and is stored in a #std::unique_ptr
|
||||
* instead. In this scenario, the #std::unique_ptr is stored in the inline buffer.
|
||||
*/
|
||||
template<typename T> static const AnyTypeInfo &get_for_unique_ptr()
|
||||
{
|
||||
using Ptr = std::unique_ptr<T>;
|
||||
static AnyTypeInfo funcs = {
|
||||
[](void *dst, const void *src) { new (dst) Ptr(new T(**(const Ptr *)src)); },
|
||||
[](void *dst, void *src) { new (dst) Ptr(new T(std::move(**(Ptr *)src))); },
|
||||
[](void *src) { ((Ptr *)src)->~Ptr(); },
|
||||
[](const void *src) -> const void * { return &**(const Ptr *)src; },
|
||||
ExtraInfo::template get<T>()};
|
||||
return funcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when the #Any does not contain any type currently.
|
||||
*/
|
||||
static const AnyTypeInfo &get_for_empty()
|
||||
{
|
||||
static AnyTypeInfo funcs = {[](void *UNUSED(dst), const void *UNUSED(src)) {},
|
||||
[](void *UNUSED(dst), void *UNUSED(src)) {},
|
||||
[](void *UNUSED(src)) {},
|
||||
[](const void *UNUSED(src)) -> const void * { return nullptr; },
|
||||
ExtraInfo{}};
|
||||
return funcs;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used when #T is stored directly in the inline buffer of the #Any.
|
||||
*/
|
||||
template<typename ExtraInfo, typename T>
|
||||
static constexpr AnyTypeInfo<ExtraInfo> info_for_inline = {
|
||||
[](void *dst, const void *src) { new (dst) T(*(const T *)src); },
|
||||
[](void *dst, void *src) { new (dst) T(std::move(*(T *)src)); },
|
||||
[](void *src) { ((T *)src)->~T(); },
|
||||
[](const void *src) { return src; },
|
||||
ExtraInfo::template get<T>()};
|
||||
|
||||
/**
|
||||
* Used when #T can't be stored directly in the inline buffer and is stored in a #std::unique_ptr
|
||||
* instead. In this scenario, the #std::unique_ptr is stored in the inline buffer.
|
||||
*/
|
||||
template<typename T> using Ptr = std::unique_ptr<T>;
|
||||
template<typename ExtraInfo, typename T>
|
||||
static constexpr AnyTypeInfo<ExtraInfo> info_for_unique_ptr = {
|
||||
[](void *dst, const void *src) { new (dst) Ptr<T>(new T(**(const Ptr<T> *)src)); },
|
||||
[](void *dst, void *src) { new (dst) Ptr<T>(new T(std::move(**(Ptr<T> *)src))); },
|
||||
[](void *src) { ((Ptr<T> *)src)->~Ptr<T>(); },
|
||||
[](const void *src) -> const void * { return &**(const Ptr<T> *)src; },
|
||||
ExtraInfo::template get<T>()};
|
||||
|
||||
/**
|
||||
* Dummy extra info that is used when no additional type information should be stored in the #Any.
|
||||
*/
|
||||
struct NoExtraInfo {
|
||||
template<typename T> static NoExtraInfo get()
|
||||
template<typename T> static constexpr NoExtraInfo get()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
@ -119,8 +101,9 @@ class Any {
|
|||
|
||||
/**
|
||||
* Information about the type that is currently stored.
|
||||
* This is null when the #Any does not contain a value.
|
||||
*/
|
||||
const Info *info_ = &Info::get_for_empty();
|
||||
const Info *info_ = nullptr;
|
||||
|
||||
public:
|
||||
/** Only copy constructible types can be stored in #Any. */
|
||||
|
@ -148,10 +131,10 @@ class Any {
|
|||
using DecayT = std::decay_t<T>;
|
||||
static_assert(is_allowed_v<DecayT>);
|
||||
if constexpr (is_inline_v<DecayT>) {
|
||||
return Info::template get_for_inline<DecayT>();
|
||||
return detail::template info_for_inline<RealExtraInfo, DecayT>;
|
||||
}
|
||||
else {
|
||||
return Info::template get_for_unique_ptr<DecayT>();
|
||||
return detail::template info_for_unique_ptr<RealExtraInfo, DecayT>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +143,9 @@ class Any {
|
|||
|
||||
Any(const Any &other) : info_(other.info_)
|
||||
{
|
||||
info_->copy_construct(&buffer_, &other.buffer_);
|
||||
if (info_ != nullptr) {
|
||||
info_->copy_construct(&buffer_, &other.buffer_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,7 +154,9 @@ class Any {
|
|||
*/
|
||||
Any(Any &&other) noexcept : info_(other.info_)
|
||||
{
|
||||
info_->move_construct(&buffer_, &other.buffer_);
|
||||
if (info_ != nullptr) {
|
||||
info_->move_construct(&buffer_, &other.buffer_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,18 +165,7 @@ class Any {
|
|||
*/
|
||||
template<typename T, typename... Args> explicit Any(std::in_place_type_t<T>, Args &&...args)
|
||||
{
|
||||
using DecayT = std::decay_t<T>;
|
||||
static_assert(is_allowed_v<DecayT>);
|
||||
info_ = &this->template get_info<DecayT>();
|
||||
if constexpr (is_inline_v<DecayT>) {
|
||||
/* Construct the value directly in the inline buffer. */
|
||||
new (&buffer_) DecayT(std::forward<Args>(args)...);
|
||||
}
|
||||
else {
|
||||
/* Construct the value in a new allocation and store a #std::unique_ptr to it in the inline
|
||||
* buffer. */
|
||||
new (&buffer_) std::unique_ptr<DecayT>(new DecayT(std::forward<Args>(args)...));
|
||||
}
|
||||
this->emplace_on_empty<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -202,7 +178,9 @@ class Any {
|
|||
|
||||
~Any()
|
||||
{
|
||||
info_->destruct(&buffer_);
|
||||
if (info_ != nullptr) {
|
||||
info_->destruct(&buffer_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -234,8 +212,10 @@ class Any {
|
|||
/** Destruct any existing value to make it empty. */
|
||||
void reset()
|
||||
{
|
||||
info_->destruct(&buffer_);
|
||||
info_ = &Info::get_for_empty();
|
||||
if (info_ != nullptr) {
|
||||
info_->destruct(&buffer_);
|
||||
}
|
||||
info_ = nullptr;
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
|
@ -245,7 +225,7 @@ class Any {
|
|||
|
||||
bool has_value() const
|
||||
{
|
||||
return info_ != &Info::get_for_empty();
|
||||
return info_ != nullptr;
|
||||
}
|
||||
|
||||
template<typename T, typename... Args> std::decay_t<T> &emplace(Args &&...args)
|
||||
|
@ -255,6 +235,26 @@ class Any {
|
|||
return this->get<T>();
|
||||
}
|
||||
|
||||
template<typename T, typename... Args> std::decay_t<T> &emplace_on_empty(Args &&...args)
|
||||
{
|
||||
BLI_assert(!this->has_value());
|
||||
using DecayT = std::decay_t<T>;
|
||||
static_assert(is_allowed_v<DecayT>);
|
||||
info_ = &this->template get_info<DecayT>();
|
||||
if constexpr (is_inline_v<DecayT>) {
|
||||
/* Construct the value directly in the inline buffer. */
|
||||
DecayT *stored_value = new (&buffer_) DecayT(std::forward<Args>(args)...);
|
||||
return *stored_value;
|
||||
}
|
||||
else {
|
||||
/* Construct the value in a new allocation and store a #std::unique_ptr to it in the inline
|
||||
* buffer. */
|
||||
std::unique_ptr<DecayT> *stored_value = new (&buffer_)
|
||||
std::unique_ptr<DecayT>(new DecayT(std::forward<Args>(args)...));
|
||||
return **stored_value;
|
||||
}
|
||||
}
|
||||
|
||||
/** Return true when the value that is currently stored is a #T. */
|
||||
template<typename T> bool is() const
|
||||
{
|
||||
|
@ -264,12 +264,14 @@ class Any {
|
|||
/** Get a pointer to the stored value. */
|
||||
void *get()
|
||||
{
|
||||
BLI_assert(info_ != nullptr);
|
||||
return const_cast<void *>(info_->get(&buffer_));
|
||||
}
|
||||
|
||||
/** Get a pointer to the stored value. */
|
||||
const void *get() const
|
||||
{
|
||||
BLI_assert(info_ != nullptr);
|
||||
return info_->get(&buffer_);
|
||||
}
|
||||
|
||||
|
@ -298,6 +300,7 @@ class Any {
|
|||
*/
|
||||
const RealExtraInfo &extra_info() const
|
||||
{
|
||||
BLI_assert(info_ != nullptr);
|
||||
return info_->extra_info;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -83,7 +83,7 @@ struct GVArrayAnyExtraInfo {
|
|||
const GVArrayImpl *(*get_varray)(const void *buffer) =
|
||||
[](const void *UNUSED(buffer)) -> const GVArrayImpl * { return nullptr; };
|
||||
|
||||
template<typename StorageT> static GVArrayAnyExtraInfo get();
|
||||
template<typename StorageT> static constexpr GVArrayAnyExtraInfo get();
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
|
@ -810,7 +810,7 @@ inline bool GVArrayCommon::is_empty() const
|
|||
* \{ */
|
||||
|
||||
namespace detail {
|
||||
template<typename StorageT> inline GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get()
|
||||
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>>);
|
||||
|
|
|
@ -564,10 +564,9 @@ template<typename T> struct VArrayAnyExtraInfo {
|
|||
/**
|
||||
* Gets the virtual array that is stored at the given pointer.
|
||||
*/
|
||||
const VArrayImpl<T> *(*get_varray)(const void *buffer) =
|
||||
[](const void *UNUSED(buffer)) -> const VArrayImpl<T> * { return nullptr; };
|
||||
const VArrayImpl<T> *(*get_varray)(const void *buffer);
|
||||
|
||||
template<typename StorageT> static VArrayAnyExtraInfo get()
|
||||
template<typename StorageT> static constexpr VArrayAnyExtraInfo get()
|
||||
{
|
||||
/* These are the only allowed types in the #Any. */
|
||||
static_assert(
|
||||
|
@ -711,6 +710,9 @@ template<typename T> class VArrayCommon {
|
|||
* null. */
|
||||
const VArrayImpl<T> *impl_from_storage() const
|
||||
{
|
||||
if (!storage_.has_value()) {
|
||||
return nullptr;
|
||||
}
|
||||
return storage_.extra_info().get_varray(storage_.get());
|
||||
}
|
||||
|
||||
|
|
|
@ -643,6 +643,9 @@ void GVArrayCommon::get_internal_single_to_uninitialized(void *r_value) const
|
|||
|
||||
const GVArrayImpl *GVArrayCommon::impl_from_storage() const
|
||||
{
|
||||
if (!storage_.has_value()) {
|
||||
return nullptr;
|
||||
}
|
||||
return storage_.extra_info().get_varray(storage_.get());
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ TEST(any, AssignAny)
|
|||
struct ExtraSizeInfo {
|
||||
size_t size;
|
||||
|
||||
template<typename T> static ExtraSizeInfo get()
|
||||
template<typename T> static constexpr ExtraSizeInfo get()
|
||||
{
|
||||
return {sizeof(T)};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue