[Bf-blender-cvs] [e3c76f79372] master: Fix libmv eigen alignment issues when compiling with AVX support

Sebastian Parborg noreply at git.blender.org
Mon Oct 19 13:06:42 CEST 2020


Commit: e3c76f793724cd7e0ade4dc610b104fb9996901c
Author: Sebastian Parborg
Date:   Mon Oct 19 13:03:06 2020 +0200
Branches: master
https://developer.blender.org/rBe3c76f793724cd7e0ade4dc610b104fb9996901c

Fix libmv eigen alignment issues when compiling with AVX support

There would be eigen alignment issues with the custom libmv vector
class when compiling with AVX optimizations. This would lead to
segfaults.

Simply use the std::vector base class as suggested by the old TODO in
the class header.

Reviewed By: Sergey

Differential Revision: http://developer.blender.org/D8968

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

M	intern/libmv/libmv/base/vector.h
M	intern/libmv/libmv/base/vector_test.cc

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

diff --git a/intern/libmv/libmv/base/vector.h b/intern/libmv/libmv/base/vector.h
index bdc4392155c..300291c5679 100644
--- a/intern/libmv/libmv/base/vector.h
+++ b/intern/libmv/libmv/base/vector.h
@@ -25,151 +25,18 @@
 #ifndef LIBMV_BASE_VECTOR_H
 #define LIBMV_BASE_VECTOR_H
 
-#include <cstring>
-#include <new>
+#include <vector>
 
 #include <Eigen/Core>
 
 namespace libmv {
 
-// A simple container class, which guarantees 16 byte alignment needed for most
-// vectorization. Don't use this container for classes that cannot be copied
-// via memcpy.
-// FIXME: this class has some issues:
-// - doesn't support iterators.
-// - impede compatibility with code using STL.
-// - the STL already provide support for custom allocators
-// it could be replaced with a simple
-// template <T> class vector : std::vector<T, aligned_allocator> {} declaration
-// provided it doesn't break code relying on libmv::vector specific behavior
-template <typename T,
-          typename Allocator = Eigen::aligned_allocator<T> >
-class vector {
- public:
-  ~vector()                        { clear();                 }
+// A simple container class, which guarantees the correct memory alignment
+// needed for most eigen vectorization. Don't use this container for classes
+// that cannot be copied via memcpy.
 
-  vector()                         { init();                  }
-  vector(int size)                 { init(); resize(size);    }
-  vector(int size, const T & val)  {
-    init();
-    resize(size);
-    std::fill(data_, data_+size_, val); }
-
-  // Copy constructor and assignment.
-  vector(const vector<T, Allocator> &rhs) {
-    init();
-    copy(rhs);
-  }
-  vector<T, Allocator> &operator=(const vector<T, Allocator> &rhs) {
-    if (&rhs != this) {
-      copy(rhs);
-    }
-    return *this;
-  }
-
-  /// Swaps the contents of two vectors in constant time.
-  void swap(vector<T, Allocator> &other) {
-    std::swap(allocator_, other.allocator_);
-    std::swap(size_, other.size_);
-    std::swap(capacity_, other.capacity_);
-    std::swap(data_, other.data_);
-  }
-
-        T *data()            const { return data_;            }
-  int      size()            const { return size_;            }
-  int      capacity()        const { return capacity_;        }
-  const T& back()            const { return data_[size_ - 1]; }
-        T& back()                  { return data_[size_ - 1]; }
-  const T& front()           const { return data_[0];         }
-        T& front()                 { return data_[0];         }
-  const T& operator[](int n) const { return data_[n];         }
-        T& operator[](int n)       { return data_[n];         }
-  const T& at(int n)         const { return data_[n];         }
-        T& at(int n)               { return data_[n];         }
-  const T * begin()          const { return data_;            }
-  const T * end()            const { return data_+size_;      }
-        T * begin()                { return data_;            }
-        T * end()                  { return data_+size_;      }
-
-  void resize(size_t size) {
-    reserve(size);
-    if (size > size_) {
-      construct(size_, size);
-    } else if (size < size_) {
-      destruct(size, size_);
-    }
-    size_ = size;
-  }
-
-  void push_back(const T &value) {
-    if (size_ == capacity_) {
-      reserve(size_ ? 2 * size_ : 1);
-    }
-    new (&data_[size_++]) T(value);
-  }
-
-  void pop_back() {
-    resize(size_ - 1);
-  }
-
-  void clear() {
-    destruct(0, size_);
-    deallocate();
-    init();
-  }
-
-  void reserve(unsigned int size) {
-    if (size > size_) {
-      T *data = static_cast<T *>(allocate(size));
-      memcpy(static_cast<void *>(data), data_, sizeof(*data)*size_);
-      allocator_.deallocate(data_, capacity_);
-      data_ = data;
-      capacity_ = size;
-    }
-  }
-
-  bool empty() {
-    return size_ == 0;
-  }
-
- private:
-  void construct(int start, int end) {
-    for (int i = start; i < end; ++i) {
-      new (&data_[i]) T;
-    }
-  }
-  void destruct(int start, int end) {
-    for (int i = start; i < end; ++i) {
-      data_[i].~T();
-    }
-  }
-  void init() {
-    size_ = 0;
-    data_ = 0;
-    capacity_ = 0;
-  }
-
-  void *allocate(int size) {
-    return size ? allocator_.allocate(size) : 0;
-  }
-
-  void deallocate() {
-    allocator_.deallocate(data_, size_);
-    data_ = 0;
-  }
-
-  void copy(const vector<T, Allocator> &rhs) {
-    resize(rhs.size());
-    for (int i = 0; i < rhs.size(); ++i) {
-      (*this)[i] = rhs[i];
-    }
-  }
-
-  Allocator allocator_;
-  size_t size_;
-  size_t capacity_;
-  T *data_;
-};
+template <class ElementType>
+using vector = std::vector<ElementType, Eigen::aligned_allocator<ElementType>>;
 
 }  // namespace libmv
 
diff --git a/intern/libmv/libmv/base/vector_test.cc b/intern/libmv/libmv/base/vector_test.cc
index f17718c3926..44b9a152148 100644
--- a/intern/libmv/libmv/base/vector_test.cc
+++ b/intern/libmv/libmv/base/vector_test.cc
@@ -115,31 +115,24 @@ TEST_F(VectorTest, ResizeConstructsAndDestructsAsExpected) {
   // Create one object.
   v.resize(1);
   EXPECT_EQ(1, v.size());
-  EXPECT_EQ(1, v.capacity());
   EXPECT_EQ(1, foo_construct_calls);
-  EXPECT_EQ(0, foo_destruct_calls);
   EXPECT_EQ(5, v[0].value);
 
   // Create two more.
   v.resize(3);
   EXPECT_EQ(3, v.size());
-  EXPECT_EQ(3, v.capacity());
   EXPECT_EQ(3, foo_construct_calls);
-  EXPECT_EQ(0, foo_destruct_calls);
 
   // Delete the last one.
   v.resize(2);
   EXPECT_EQ(2, v.size());
   EXPECT_EQ(3, v.capacity());
   EXPECT_EQ(3, foo_construct_calls);
-  EXPECT_EQ(1, foo_destruct_calls);
 
   // Delete the remaining two.
   v.resize(0);
   EXPECT_EQ(0, v.size());
-  EXPECT_EQ(3, v.capacity());
   EXPECT_EQ(3, foo_construct_calls);
-  EXPECT_EQ(3, foo_destruct_calls);
 }
 
 TEST_F(VectorTest, PushPopBack) {
@@ -192,15 +185,15 @@ TEST_F(VectorTest, STLFind) {
   a.push_back(5);
   a.push_back(3);
 
-  // Find return an int *
+  // Find returns an int *
   EXPECT_EQ(std::find(&a[0], &a[2], 1) == &a[0], true);
   EXPECT_EQ(std::find(&a[0], &a[2], 5) == &a[1], true);
   EXPECT_EQ(std::find(&a[0], &a[2], 3) == &a[2], true);
 
-  // Find return a const int *
-  EXPECT_EQ(std::find(a.begin(), a.end(), 1) == &a[0], true);
-  EXPECT_EQ(std::find(a.begin(), a.end(), 5) == &a[1], true);
-  EXPECT_EQ(std::find(a.begin(), a.end(), 3) == &a[2], true);
+  // Find returns an interator
+  EXPECT_EQ(std::find(a.begin(), a.end(), 1) == std::next(a.begin(), 0), true);
+  EXPECT_EQ(std::find(a.begin(), a.end(), 5) == std::next(a.begin(), 1), true);
+  EXPECT_EQ(std::find(a.begin(), a.end(), 3) == std::next(a.begin(), 2), true);
 
   // Search value that are not in the vector
   EXPECT_EQ(std::find(a.begin(), a.end(), 0) == a.end(), true);



More information about the Bf-blender-cvs mailing list