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 /source/blender/blenlib/BLI_any.hh | |
parent | c63d64a2ce3e49188628d54450b751fd764b8a67 (diff) |
BLI: optimize constructing new virtual array
Differential Revision: https://developer.blender.org/D14745
Diffstat (limited to 'source/blender/blenlib/BLI_any.hh')
-rw-r--r-- | source/blender/blenlib/BLI_any.hh | 129 |
1 files changed, 66 insertions, 63 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; } }; |