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.
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user