From a337e7738fbf2ec1eaec4c1deb46d28840885758 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 25 May 2022 16:28:07 +0200 Subject: [PATCH] BLI: use no_unique_address attribute Even though the `no_unique_address` attribute has only been standardized in C++20, compilers seem to support it with C++17 already. This attribute allows reducing the memory footprint of structs which have empty types as data members (usually that is an allocator or inline buffer in Blender). Previously, one had to use the empty base optimization to achieve the same effect, which requires a lot of boilerplate code. The types that benefit from this the most are `Vector` and `Array`, which usually become 8 bytes smaller. All types which use these core data structures get smaller as well of course. Differential Revision: https://developer.blender.org/D14993 --- CMakeLists.txt | 1 + source/blender/blenlib/BLI_array.hh | 4 ++-- source/blender/blenlib/BLI_generic_array.hh | 2 +- .../blender/blenlib/BLI_linear_allocator.hh | 2 +- source/blender/blenlib/BLI_map.hh | 4 ++-- source/blender/blenlib/BLI_memory_utils.hh | 24 ++++++++++++------- source/blender/blenlib/BLI_set.hh | 4 ++-- source/blender/blenlib/BLI_stack.hh | 4 ++-- source/blender/blenlib/BLI_utildefines.h | 12 ++++++++++ source/blender/blenlib/BLI_vector.hh | 4 ++-- source/blender/blenlib/BLI_vector_set.hh | 4 ++-- 11 files changed, 42 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 85827e01af5..3e97e393f17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1756,6 +1756,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC") "/wd4828" # The file contains a character that is illegal "/wd4996" # identifier was declared deprecated "/wd4661" # no suitable definition provided for explicit template instantiation request + "/wd4848" # 'no_unique_address' is a vendor extension in C++17 # errors: "/we4013" # 'function' undefined; assuming extern returning int "/we4133" # incompatible pointer types diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh index 91dfc81ae27..813277d9968 100644 --- a/source/blender/blenlib/BLI_array.hh +++ b/source/blender/blenlib/BLI_array.hh @@ -64,10 +64,10 @@ class Array { int64_t size_; /** Used for allocations when the inline buffer is too small. */ - Allocator allocator_; + BLI_NO_UNIQUE_ADDRESS Allocator allocator_; /** A placeholder buffer that will remain uninitialized until it is used. */ - TypedBuffer inline_buffer_; + BLI_NO_UNIQUE_ADDRESS TypedBuffer inline_buffer_; public: /** diff --git a/source/blender/blenlib/BLI_generic_array.hh b/source/blender/blenlib/BLI_generic_array.hh index e1b6b29874a..4b917434264 100644 --- a/source/blender/blenlib/BLI_generic_array.hh +++ b/source/blender/blenlib/BLI_generic_array.hh @@ -33,7 +33,7 @@ class GArray { void *data_ = nullptr; int64_t size_ = 0; - Allocator allocator_; + BLI_NO_UNIQUE_ADDRESS Allocator allocator_; public: /** diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh index 6532c59a846..deb6ea3b5fd 100644 --- a/source/blender/blenlib/BLI_linear_allocator.hh +++ b/source/blender/blenlib/BLI_linear_allocator.hh @@ -18,7 +18,7 @@ namespace blender { template class LinearAllocator : NonCopyable, NonMovable { private: - Allocator allocator_; + BLI_NO_UNIQUE_ADDRESS Allocator allocator_; Vector owned_buffers_; Vector> unused_borrowed_buffers_; diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh index d76aa46502d..55233676ed8 100644 --- a/source/blender/blenlib/BLI_map.hh +++ b/source/blender/blenlib/BLI_map.hh @@ -130,10 +130,10 @@ class Map { uint64_t slot_mask_; /** This is called to hash incoming keys. */ - Hash hash_; + BLI_NO_UNIQUE_ADDRESS Hash hash_; /** This is called to check equality of two keys. */ - IsEqual is_equal_; + BLI_NO_UNIQUE_ADDRESS IsEqual is_equal_; /** The max load factor is 1/2 = 50% by default. */ #define LOAD_FACTOR 1, 2 diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index d7c41ae88a8..940542c9f1d 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -317,30 +317,36 @@ template using destruct_ptr = std::unique_ptr class alignas(Alignment) AlignedBuffer { - private: - /* Don't create an empty array. This causes problems with some compilers. */ - char buffer_[(Size > 0) ? Size : 1]; +template class AlignedBuffer { + struct Empty { + }; + struct alignas(Alignment) Sized { + /* Don't create an empty array. This causes problems with some compilers. */ + std::byte buffer_[Size > 0 ? Size : 1]; + }; + + using BufferType = std::conditional_t; + BLI_NO_UNIQUE_ADDRESS BufferType buffer_; public: operator void *() { - return buffer_; + return this; } operator const void *() const { - return buffer_; + return this; } void *ptr() { - return buffer_; + return this; } const void *ptr() const { - return buffer_; + return this; } }; @@ -351,7 +357,7 @@ template class alignas(Alignment) AlignedBuffer { */ template class TypedBuffer { private: - AlignedBuffer buffer_; + BLI_NO_UNIQUE_ADDRESS AlignedBuffer buffer_; public: operator T *() diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh index 99acae43571..62de4b79e41 100644 --- a/source/blender/blenlib/BLI_set.hh +++ b/source/blender/blenlib/BLI_set.hh @@ -136,10 +136,10 @@ class Set { uint64_t slot_mask_; /** This is called to hash incoming keys. */ - Hash hash_; + BLI_NO_UNIQUE_ADDRESS Hash hash_; /** This is called to check equality of two keys. */ - IsEqual is_equal_; + BLI_NO_UNIQUE_ADDRESS IsEqual is_equal_; /** The max load factor is 1/2 = 50% by default. */ #define LOAD_FACTOR 1, 2 diff --git a/source/blender/blenlib/BLI_stack.hh b/source/blender/blenlib/BLI_stack.hh index a06515a7781..ed123f43a6b 100644 --- a/source/blender/blenlib/BLI_stack.hh +++ b/source/blender/blenlib/BLI_stack.hh @@ -96,7 +96,7 @@ class Stack { int64_t size_; /** The buffer used to implement small object optimization. */ - TypedBuffer inline_buffer_; + BLI_NO_UNIQUE_ADDRESS TypedBuffer inline_buffer_; /** * A chunk referencing the inline buffer. This is always the bottom-most chunk. @@ -105,7 +105,7 @@ class Stack { Chunk inline_chunk_; /** Used for allocations when the inline buffer is not large enough. */ - Allocator allocator_; + BLI_NO_UNIQUE_ADDRESS Allocator allocator_; public: /** diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index b8407a5453f..7f9470a9111 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -843,6 +843,18 @@ extern bool BLI_memory_is_zero(const void *arr, size_t arr_size); */ #define BLI_ENABLE_IF(condition) typename std::enable_if_t<(condition)> * = nullptr +#if defined(_MSC_VER) +# define BLI_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] +#elif defined(__has_cpp_attribute) +# if __has_cpp_attribute(no_unique_address) +# define BLI_NO_UNIQUE_ADDRESS [[no_unique_address]] +# else +# define BLI_NO_UNIQUE_ADDRESS +# endif +#else +# define BLI_NO_UNIQUE_ADDRESS [[no_unique_address]] +#endif + /** \} */ #ifdef __cplusplus diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh index acf47f67168..c23d846d277 100644 --- a/source/blender/blenlib/BLI_vector.hh +++ b/source/blender/blenlib/BLI_vector.hh @@ -84,10 +84,10 @@ class Vector { T *capacity_end_; /** Used for allocations when the inline buffer is too small. */ - Allocator allocator_; + BLI_NO_UNIQUE_ADDRESS Allocator allocator_; /** A placeholder buffer that will remain uninitialized until it is used. */ - TypedBuffer inline_buffer_; + BLI_NO_UNIQUE_ADDRESS TypedBuffer inline_buffer_; /** * Store the size of the vector explicitly in debug builds. Otherwise you'd always have to call diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh index 4ae1bf9000d..b0a3696f245 100644 --- a/source/blender/blenlib/BLI_vector_set.hh +++ b/source/blender/blenlib/BLI_vector_set.hh @@ -117,10 +117,10 @@ class VectorSet { uint64_t slot_mask_; /** This is called to hash incoming keys. */ - Hash hash_; + BLI_NO_UNIQUE_ADDRESS Hash hash_; /** This is called to check equality of two keys. */ - IsEqual is_equal_; + BLI_NO_UNIQUE_ADDRESS IsEqual is_equal_; /** The max load factor is 1/2 = 50% by default. */ #define LOAD_FACTOR 1, 2