diff options
author | Jacques Lucke <jacques@blender.org> | 2020-06-30 16:58:14 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2020-06-30 16:58:29 +0300 |
commit | 37820651bb4f22e316f00a02e4bf5da2589a03c9 (patch) | |
tree | d5a720582e58c151c61a09304f5b354516283899 | |
parent | 5b03f49302a39577f2373906cfba19feebfaa9ba (diff) |
BLI: add Array constructor that does not initialize non-trivial types
This should rarely be necessary, but I have a use case coming up soon.
-rw-r--r-- | source/blender/blenlib/BLI_array.hh | 21 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_memory_utils.hh | 7 | ||||
-rw-r--r-- | tests/gtests/blenlib/BLI_array_test.cc | 35 |
3 files changed, 61 insertions, 2 deletions
diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh index 07155439170..25267bc65d6 100644 --- a/source/blender/blenlib/BLI_array.hh +++ b/source/blender/blenlib/BLI_array.hh @@ -27,8 +27,7 @@ * blender::Array should usually be used instead of blender::Vector whenever the number of elements * is known at construction time. Note however, that blender::Array will default construct all * elements when initialized with the size-constructor. For trivial types, this does nothing. In - * all other cases, this adds overhead. If this becomes a problem, a different constructor which - * does not do default construction can be added. + * all other cases, this adds overhead. * * A main benefit of using Array over Vector is that it expresses the intent of the developer * better. It indicates that the size of the data structure is not expected to change. Furthermore, @@ -130,6 +129,24 @@ class Array { uninitialized_fill_n(m_data, m_size, value); } + /** + * Create a new array with uninitialized elements. The caller is responsible for constructing the + * elements. Moving, copying or destructing an Array with uninitialized elements invokes + * undefined behavior. + * + * This should be used very rarely. Note, that the normal size-constructor also does not + * initialize the elements when T is trivially constructible. Therefore, it only makes sense to + * use this with non trivially constructible types. + * + * Usage: + * Array<std::string> my_strings(10, NoInitialization()); + */ + Array(uint size, NoInitialization) + { + m_size = size; + m_data = this->get_buffer_for_size(size); + } + Array(const Array &other) : m_allocator(other.m_allocator) { m_size = other.size(); diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index baad862bce5..0c2cae6c606 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -242,6 +242,13 @@ template<size_t Size, size_t Alignment> class alignas(Alignment) AlignedBuffer { } }; +/** + * This can be used by container constructors. A parameter of this type should be used to indicate + * that the constructor does not construct the elements. + */ +class NoInitialization { +}; + } // namespace blender #endif /* __BLI_MEMORY_UTILS_HH__ */ diff --git a/tests/gtests/blenlib/BLI_array_test.cc b/tests/gtests/blenlib/BLI_array_test.cc index 9ff4dc9a371..08f61a19900 100644 --- a/tests/gtests/blenlib/BLI_array_test.cc +++ b/tests/gtests/blenlib/BLI_array_test.cc @@ -124,3 +124,38 @@ TEST(array, TrivialTypeSizeConstructor) EXPECT_EQ(*ptr, magic); delete array; } + +struct ConstructibleType { + char value; + + ConstructibleType() + { + value = 42; + } +}; + +TEST(array, NoInitializationSizeConstructor) +{ + using MyArray = Array<ConstructibleType>; + + AlignedBuffer<sizeof(MyArray), alignof(MyArray)> buffer; + char *buffer_ptr = (char *)buffer.ptr(); + memset(buffer_ptr, 100, sizeof(MyArray)); + + /* Doing this to avoid some compiler optimization. */ + for (uint i : IndexRange(sizeof(MyArray))) { + EXPECT_EQ(buffer_ptr[i], 100); + } + + { + MyArray &array = *new (buffer.ptr()) MyArray(1, NoInitialization()); + EXPECT_EQ(array[0].value, 100); + array.clear_without_destruct(); + array.~Array(); + } + { + MyArray &array = *new (buffer.ptr()) MyArray(1); + EXPECT_EQ(array[0].value, 42); + array.~Array(); + } +} |