diff options
author | Jacques Lucke <jacques@blender.org> | 2022-06-25 20:27:33 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2022-06-25 20:27:33 +0300 |
commit | 22fc0cbd6966c1e46a28038fca8ef59e8ce50660 (patch) | |
tree | 0f6bf65b27f60f7f313fa14daefa662eb3e4678e /source/blender/blenlib/BLI_any.hh | |
parent | 3237c6dbe877db1cfbe15e92f6cb267d8a6031ea (diff) |
BLI: improve support for trivial virtual arrays
This commits reduces the number of function calls through function
pointers in `blender::Any` when the stored type is trivial.
Furthermore, this implements marks some classes as trivial, which
we know are trivial but the compiler does not (the standard currently
says that any class with a virtual destructor is non-trivial). Under some
circumstances we know that final child classes are trivial though.
This allows for some optimizations.
Also see https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1077r0.html.
Diffstat (limited to 'source/blender/blenlib/BLI_any.hh')
-rw-r--r-- | source/blender/blenlib/BLI_any.hh | 51 |
1 files changed, 40 insertions, 11 deletions
diff --git a/source/blender/blenlib/BLI_any.hh b/source/blender/blenlib/BLI_any.hh index e80dad82d01..a20239f214f 100644 --- a/source/blender/blenlib/BLI_any.hh +++ b/source/blender/blenlib/BLI_any.hh @@ -13,6 +13,7 @@ */ #include <algorithm> +#include <cstring> #include <utility> #include "BLI_memory_utils.hh" @@ -26,6 +27,7 @@ namespace detail { * Additional type specific #ExtraInfo can be embedded here as well. */ template<typename ExtraInfo> struct AnyTypeInfo { + /* The pointers are allowed to be null, which means that the implementation is trivial. */ void (*copy_construct)(void *dst, const void *src); void (*move_construct)(void *dst, void *src); void (*destruct)(void *src); @@ -38,10 +40,15 @@ template<typename ExtraInfo> struct AnyTypeInfo { */ 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) { std::destroy_at(((T *)src)); }, - [](const void *src) { return src; }, + is_trivially_copy_constructible_extended_v<T> ? + nullptr : + +[](void *dst, const void *src) { new (dst) T(*(const T *)src); }, + is_trivially_move_constructible_extended_v<T> ? + nullptr : + +[](void *dst, void *src) { new (dst) T(std::move(*(T *)src)); }, + is_trivially_destructible_extended_v<T> ? nullptr : + +[](void *src) { std::destroy_at(((T *)src)); }, + nullptr, ExtraInfo::template get<T>()}; /** @@ -92,12 +99,14 @@ class Any { using RealExtraInfo = std::conditional_t<std::is_void_v<ExtraInfo>, detail::NoExtraInfo, ExtraInfo>; using Info = detail::AnyTypeInfo<RealExtraInfo>; + static constexpr size_t RealInlineBufferCapacity = std::max(InlineBufferCapacity, + sizeof(std::unique_ptr<int>)); /** * Inline buffer that either contains nothing, the stored value directly, or a #std::unique_ptr * to the value. */ - AlignedBuffer<std::max(InlineBufferCapacity, sizeof(std::unique_ptr<int>)), Alignment> buffer_{}; + AlignedBuffer<RealInlineBufferCapacity, Alignment> buffer_{}; /** * Information about the type that is currently stored. @@ -144,7 +153,12 @@ class Any { Any(const Any &other) : info_(other.info_) { if (info_ != nullptr) { - info_->copy_construct(&buffer_, &other.buffer_); + if (info_->copy_construct != nullptr) { + info_->copy_construct(&buffer_, &other.buffer_); + } + else { + memcpy(&buffer_, &other.buffer_, RealInlineBufferCapacity); + } } } @@ -155,7 +169,12 @@ class Any { Any(Any &&other) noexcept : info_(other.info_) { if (info_ != nullptr) { - info_->move_construct(&buffer_, &other.buffer_); + if (info_->move_construct != nullptr) { + info_->move_construct(&buffer_, &other.buffer_); + } + else { + memcpy(&buffer_, &other.buffer_, RealInlineBufferCapacity); + } } } @@ -179,7 +198,9 @@ class Any { ~Any() { if (info_ != nullptr) { - info_->destruct(&buffer_); + if (info_->destruct != nullptr) { + info_->destruct(&buffer_); + } } } @@ -213,7 +234,9 @@ class Any { void reset() { if (info_ != nullptr) { - info_->destruct(&buffer_); + if (info_->destruct != nullptr) { + info_->destruct(&buffer_); + } } info_ = nullptr; } @@ -265,14 +288,20 @@ class Any { void *get() { BLI_assert(info_ != nullptr); - return const_cast<void *>(info_->get(&buffer_)); + if (info_->get != nullptr) { + return const_cast<void *>(info_->get(&buffer_)); + } + return &buffer_; } /** Get a pointer to the stored value. */ const void *get() const { BLI_assert(info_ != nullptr); - return info_->get(&buffer_); + if (info_->get != nullptr) { + return info_->get(&buffer_); + } + return &buffer_; } /** |