[Bf-blender-cvs] [37820651bb4] master: BLI: add Array constructor that does not initialize non-trivial types

Jacques Lucke noreply at git.blender.org
Tue Jun 30 15:58:42 CEST 2020


Commit: 37820651bb4f22e316f00a02e4bf5da2589a03c9
Author: Jacques Lucke
Date:   Tue Jun 30 15:58:14 2020 +0200
Branches: master
https://developer.blender.org/rB37820651bb4f22e316f00a02e4bf5da2589a03c9

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.

===================================================================

M	source/blender/blenlib/BLI_array.hh
M	source/blender/blenlib/BLI_memory_utils.hh
M	tests/gtests/blenlib/BLI_array_test.cc

===================================================================

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();
+  }
+}



More information about the Bf-blender-cvs mailing list