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 | |
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')
-rw-r--r-- | source/blender/blenlib/BLI_any.hh | 51 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_generic_virtual_array.hh | 5 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_memory_utils.hh | 17 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_virtual_array.hh | 13 |
4 files changed, 74 insertions, 12 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_; } /** diff --git a/source/blender/blenlib/BLI_generic_virtual_array.hh b/source/blender/blenlib/BLI_generic_virtual_array.hh index b4bd337805f..95305a0561d 100644 --- a/source/blender/blenlib/BLI_generic_virtual_array.hh +++ b/source/blender/blenlib/BLI_generic_virtual_array.hh @@ -600,6 +600,8 @@ class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan { CommonVArrayInfo common_info() const override; }; +template<> inline constexpr bool is_trivial_extended_v<GVArrayImpl_For_GSpan_final> = true; + /** \} */ /* -------------------------------------------------------------------- */ @@ -638,6 +640,9 @@ class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_Single CommonVArrayInfo common_info() const override; }; +template<> +inline constexpr bool is_trivial_extended_v<GVArrayImpl_For_SingleValueRef_final> = true; + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index 940542c9f1d..c2ad3ea761a 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -19,6 +19,21 @@ namespace blender { /** + * Under some circumstances #std::is_trivial_v<T> is false even though we know that the type is + * actually trivial. Using that extra knowledge allows for some optimizations. + */ +template<typename T> inline constexpr bool is_trivial_extended_v = std::is_trivial_v<T>; +template<typename T> +inline constexpr bool is_trivially_destructible_extended_v = is_trivial_extended_v<T> || + std::is_trivially_destructible_v<T>; +template<typename T> +inline constexpr bool is_trivially_copy_constructible_extended_v = + is_trivial_extended_v<T> || std::is_trivially_copy_constructible_v<T>; +template<typename T> +inline constexpr bool is_trivially_move_constructible_extended_v = + is_trivial_extended_v<T> || std::is_trivially_move_constructible_v<T>; + +/** * Call the destructor on n consecutive values. For trivially destructible types, this does * nothing. * @@ -38,7 +53,7 @@ template<typename T> void destruct_n(T *ptr, int64_t n) /* This is not strictly necessary, because the loop below will be optimized away anyway. It is * nice to make behavior this explicitly, though. */ - if (std::is_trivially_destructible_v<T>) { + if (is_trivially_destructible_extended_v<T>) { return; } diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh index e34eac1a006..d0436bdc213 100644 --- a/source/blender/blenlib/BLI_virtual_array.hh +++ b/source/blender/blenlib/BLI_virtual_array.hh @@ -319,6 +319,9 @@ template<typename T> class VArrayImpl_For_Span_final final : public VArrayImpl_F } }; +template<typename T> +inline constexpr bool is_trivial_extended_v<VArrayImpl_For_Span_final<T>> = true; + /** * A variant of `VArrayImpl_For_Span` that owns the underlying data. * The `Container` type has to implement a `size()` and `data()` method. @@ -379,6 +382,9 @@ template<typename T> class VArrayImpl_For_Single final : public VArrayImpl<T> { } }; +template<typename T> +inline constexpr bool is_trivial_extended_v<VArrayImpl_For_Single<T>> = is_trivial_extended_v<T>; + /** * This class makes it easy to create a virtual array for an existing function or lambda. The * `GetFunc` should take a single `index` argument and return the value at that index. @@ -522,6 +528,13 @@ class VArrayImpl_For_DerivedSpan final : public VMutableArrayImpl<ElemT> { } }; +template<typename StructT, + typename ElemT, + ElemT (*GetFunc)(const StructT &), + void (*SetFunc)(StructT &, ElemT)> +inline constexpr bool + is_trivial_extended_v<VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>> = true; + namespace detail { /** |