[Bf-blender-cvs] [7e767d08583] functions: initial experimental vector adaptor data structure

Jacques Lucke noreply at git.blender.org
Fri Jun 28 17:41:25 CEST 2019


Commit: 7e767d08583496d7eef4fd531e0583291f79b736
Author: Jacques Lucke
Date:   Fri Jun 28 17:41:15 2019 +0200
Branches: functions
https://developer.blender.org/rB7e767d08583496d7eef4fd531e0583291f79b736

initial experimental vector adaptor data structure

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

A	source/blender/blenlib/BLI_vector_adaptor.hpp
M	source/blender/blenlib/CMakeLists.txt
A	tests/gtests/blenlib/BLI_vector_adaptor_test.cc
M	tests/gtests/blenlib/CMakeLists.txt

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

diff --git a/source/blender/blenlib/BLI_vector_adaptor.hpp b/source/blender/blenlib/BLI_vector_adaptor.hpp
new file mode 100644
index 00000000000..65691b74818
--- /dev/null
+++ b/source/blender/blenlib/BLI_vector_adaptor.hpp
@@ -0,0 +1,141 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ *
+ * This vector wraps an externally provided memory buffer.
+ * At allows using any buffer as if it were an array.
+ * It does not grow the array dynamically. If the number of
+ * elements is about to exceed the capacity, it asserts false.
+ *
+ * This constraint allows a very efficient append operation,
+ * since no boundary checks have to be performed in release builds.
+ */
+
+#pragma once
+
+#include "BLI_array_ref.hpp"
+
+namespace BLI {
+
+template<typename T> class VectorAdaptor {
+ private:
+  T *m_start;
+  T *m_end;
+  uint m_capacity;
+
+ public:
+  /**
+   * Construct an empty vector adaptor.
+   */
+  VectorAdaptor() : m_start(nullptr), m_end(nullptr), m_capacity(0)
+  {
+  }
+
+  /**
+   * Disable creating copies of the vector, because it would not be
+   * clear, where the new adaptor should take the memory from.
+   */
+  VectorAdaptor(VectorAdaptor &other) = delete;
+
+  /**
+   * Construct using any pointer and a capacity.
+   * The initial size is set to zero.
+   */
+  VectorAdaptor(T *ptr, uint capacity) : m_start(ptr), m_end(ptr), m_capacity(capacity)
+  {
+  }
+
+  /**
+   * Construct from an array. The capacity is automatically determined
+   * from the length of the array.
+   * The initial size is set to zero.
+   */
+  template<uint N> VectorAdaptor(T (&array)[N]) : m_start(array), m_end(array), m_capacity(N)
+  {
+  }
+
+  ~VectorAdaptor()
+  {
+    for (T &value : *this) {
+      value.~T();
+    }
+  }
+
+  /**
+   * Insert one element at the end of the vector.
+   * Asserts, when the capacity is exceeded.
+   */
+  void append(const T &value)
+  {
+    BLI_assert(this->size() < m_capacity);
+    std::uninitialized_copy_n(&value, 1, m_end);
+    m_end += 1;
+  }
+
+  void append(T &&value)
+  {
+    BLI_assert(this->size() < m_capacity);
+    std::uninitialized_copy_n(std::make_move_iterator(&value), 1, m_end);
+    m_end += 1;
+  }
+
+  /**
+   * Insert multiple elements at the end of the vector.
+   * Asserts, when the capacity is exceeded.
+   */
+  void extend(ArrayRef<T> values)
+  {
+    BLI_assert(this->size() + values.size() < m_capacity);
+    std::uninitialized_copy_n(values.begin(), values.size(), m_end);
+    m_end += values.size();
+  }
+
+  /**
+   * Return the maximum size of the vector.
+   */
+  uint capacity() const
+  {
+    return m_capacity;
+  }
+
+  /**
+   * Return the current size of the vector.
+   */
+  uint size() const
+  {
+    return m_end - m_start;
+  }
+
+  T &operator[](uint index)
+  {
+    BLI_assert(index < this->size());
+    return this->begin()[index];
+  }
+
+  T *begin() const
+  {
+    return m_start;
+  }
+
+  T *end() const
+  {
+    return m_end;
+  }
+};
+
+}  // namespace BLI
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 6ee3877d97a..95f703357b0 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -257,6 +257,7 @@ set(SRC
   BLI_small_stack.hpp
   BLI_string_ref.hpp
   BLI_timeit.hpp
+  BLI_vector_adaptor.hpp
 )
 
 set(LIB
diff --git a/tests/gtests/blenlib/BLI_vector_adaptor_test.cc b/tests/gtests/blenlib/BLI_vector_adaptor_test.cc
new file mode 100644
index 00000000000..b100b5a5d97
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_vector_adaptor_test.cc
@@ -0,0 +1,87 @@
+#include "testing/testing.h"
+#include "BLI_vector_adaptor.hpp"
+#include <vector>
+
+using IntVectorAdaptor = BLI::VectorAdaptor<int>;
+
+TEST(vector_adaptor, DefaultConstructor)
+{
+  IntVectorAdaptor vec;
+  EXPECT_EQ(vec.size(), 0);
+  EXPECT_EQ(vec.capacity(), 0);
+}
+
+TEST(vector_adaptor, PointerConstructor)
+{
+  int *array = new int[3];
+  IntVectorAdaptor vec(array, 3);
+  EXPECT_EQ(vec.size(), 0);
+  EXPECT_EQ(vec.capacity(), 3);
+  delete[] array;
+}
+
+TEST(vector_adaptor, ArrayConstructor)
+{
+  int array[5];
+  IntVectorAdaptor vec(array);
+  EXPECT_EQ(vec.size(), 0);
+  EXPECT_EQ(vec.capacity(), 5);
+}
+
+TEST(vector_adaptor, AppendOnce)
+{
+  int array[5];
+  IntVectorAdaptor vec(array);
+  vec.append(42);
+  EXPECT_EQ(vec.size(), 1);
+  EXPECT_EQ(vec[0], 42);
+}
+
+TEST(vector_adaptor, AppendFull)
+{
+  int array[5];
+  IntVectorAdaptor vec(array);
+  vec.append(3);
+  vec.append(4);
+  vec.append(5);
+  vec.append(6);
+  vec.append(7);
+  EXPECT_EQ(vec.size(), 5);
+  EXPECT_EQ(vec[0], 3);
+  EXPECT_EQ(vec[1], 4);
+  EXPECT_EQ(vec[2], 5);
+  EXPECT_EQ(vec[3], 6);
+  EXPECT_EQ(vec[4], 7);
+}
+
+TEST(vector_adaptor, Iterate)
+{
+  int array[4];
+  IntVectorAdaptor vec(array);
+  vec.append(10);
+  vec.append(11);
+  vec.append(12);
+
+  std::vector<int> std_vector;
+  for (int value : vec) {
+    std_vector.push_back(value);
+  }
+
+  EXPECT_EQ(std_vector.size(), 3);
+  EXPECT_EQ(std_vector[0], 10);
+  EXPECT_EQ(std_vector[1], 11);
+  EXPECT_EQ(std_vector[2], 12);
+}
+
+TEST(vector_adaptor, Extend)
+{
+  int array[6];
+  IntVectorAdaptor vec(array);
+  vec.extend({1, 3});
+  vec.extend({2, 5});
+  EXPECT_EQ(vec.size(), 4);
+  EXPECT_EQ(vec[0], 1);
+  EXPECT_EQ(vec[1], 3);
+  EXPECT_EQ(vec[2], 2);
+  EXPECT_EQ(vec[3], 5);
+}
diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt
index c342483aad0..a97efa81805 100644
--- a/tests/gtests/blenlib/CMakeLists.txt
+++ b/tests/gtests/blenlib/CMakeLists.txt
@@ -74,6 +74,7 @@ BLENDER_TEST(BLI_string "bf_blenlib")
 BLENDER_TEST(BLI_string_ref "bf_blenlib")
 BLENDER_TEST(BLI_string_utf8 "bf_blenlib")
 BLENDER_TEST(BLI_task "bf_blenlib;bf_intern_numaapi")
+BLENDER_TEST(BLI_vector_adaptor "bf_blenlib")
 
 BLENDER_TEST_PERFORMANCE(BLI_ghash_performance "bf_blenlib")
 BLENDER_TEST_PERFORMANCE(BLI_task_performance "bf_blenlib")



More information about the Bf-blender-cvs mailing list