diff options
author | Jacques Lucke <jacques@blender.org> | 2022-04-25 12:51:22 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2022-04-25 12:51:34 +0300 |
commit | a2d32960b4de78f545ce52e92185eefd3c93fde1 (patch) | |
tree | d07f2c21566f223bd62731ee06e78984caaa17f5 | |
parent | c63d64a2ce3e49188628d54450b751fd764b8a67 (diff) |
BLI: optimize constructing new virtual array
Differential Revision: https://developer.blender.org/D14745
-rw-r--r-- | source/blender/blenlib/BLI_any.hh | 129 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_generic_virtual_array.hh | 4 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_virtual_array.hh | 8 | ||||
-rw-r--r-- | source/blender/blenlib/intern/generic_virtual_array.cc | 3 | ||||
-rw-r--r-- | source/blender/blenlib/tests/BLI_any_test.cc | 2 |
5 files changed, 77 insertions, 69 deletions
diff --git a/source/blender/blenlib/BLI_any.hh b/source/blender/blenlib/BLI_any.hh index 4424ad29a21..875e7cce056 100644 --- a/source/blender/blenlib/BLI_any.hh +++ b/source/blender/blenlib/BLI_any.hh @@ -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 #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 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 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; } }; diff --git a/source/blender/blenlib/BLI_generic_virtual_array.hh b/source/blender/blenlib/BLI_generic_virtual_array.hh index 2e756e912f9..d02760d9178 100644 --- a/source/blender/blenlib/BLI_generic_virtual_array.hh +++ b/source/blender/blenlib/BLI_generic_virtual_array.hh @@ -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>>); diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh index 453ca67b1e0..41a73b45853 100644 --- a/source/blender/blenlib/BLI_virtual_array.hh +++ b/source/blender/blenlib/BLI_virtual_array.hh @@ -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()); } diff --git a/source/blender/blenlib/intern/generic_virtual_array.cc b/source/blender/blenlib/intern/generic_virtual_array.cc index e1a150c3f08..a3a17952a97 100644 --- a/source/blender/blenlib/intern/generic_virtual_array.cc +++ b/source/blender/blenlib/intern/generic_virtual_array.cc @@ -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()); } diff --git a/source/blender/blenlib/tests/BLI_any_test.cc b/source/blender/blenlib/tests/BLI_any_test.cc index 2830fe8b320..bf592e74206 100644 --- a/source/blender/blenlib/tests/BLI_any_test.cc +++ b/source/blender/blenlib/tests/BLI_any_test.cc @@ -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)}; } |