1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
5 // Copyright (C) 2006-2009 Benoit Jacob <jacob.benoit.1@gmail.com>
6 // Copyright (C) 2010 Hauke Heibel <hauke.heibel@gmail.com>
7 //
8 // This Source Code Form is subject to the terms of the Mozilla
9 // Public License v. 2.0. If a copy of the MPL was not distributed
10 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
11 
12 #ifndef EIGEN_MATRIXSTORAGE_H
13 #define EIGEN_MATRIXSTORAGE_H
14 
15 #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN
16   #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN EIGEN_DENSE_STORAGE_CTOR_PLUGIN;
17 #else
18   #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN
19 #endif
20 
21 namespace Eigen {
22 
23 namespace internal {
24 
25 struct constructor_without_unaligned_array_assert {};
26 
check_static_allocation_size()27 template<typename T, int Size> void check_static_allocation_size()
28 {
29   // if EIGEN_STACK_ALLOCATION_LIMIT is defined to 0, then no limit
30   #if EIGEN_STACK_ALLOCATION_LIMIT
31   EIGEN_STATIC_ASSERT(Size * sizeof(T) <= EIGEN_STACK_ALLOCATION_LIMIT, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG);
32   #endif
33 }
34 
35 /** \internal
36   * Static array. If the MatrixOrArrayOptions require auto-alignment, the array will be automatically aligned:
37   * to 16 bytes boundary if the total size is a multiple of 16 bytes.
38   */
39 template <typename T, int Size, int MatrixOrArrayOptions,
40           int Alignment = (MatrixOrArrayOptions&DontAlign) ? 0
41                         : (((Size*sizeof(T))%16)==0) ? 16
42                         : 0 >
43 struct plain_array
44 {
45   T array[Size];
46 
plain_arrayplain_array47   plain_array()
48   {
49     check_static_allocation_size<T,Size>();
50   }
51 
plain_arrayplain_array52   plain_array(constructor_without_unaligned_array_assert)
53   {
54     check_static_allocation_size<T,Size>();
55   }
56 };
57 
58 #if defined(EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT)
59   #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask)
60 #elif EIGEN_GNUC_AT_LEAST(4,7)
61   // GCC 4.7 is too aggressive in its optimizations and remove the alignement test based on the fact the array is declared to be aligned.
62   // See this bug report: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53900
63   // Hiding the origin of the array pointer behind a function argument seems to do the trick even if the function is inlined:
64   template<typename PtrType>
eigen_unaligned_array_assert_workaround_gcc47(PtrType array)65   EIGEN_ALWAYS_INLINE PtrType eigen_unaligned_array_assert_workaround_gcc47(PtrType array) { return array; }
66   #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \
67     eigen_assert((reinterpret_cast<size_t>(eigen_unaligned_array_assert_workaround_gcc47(array)) & sizemask) == 0 \
68               && "this assertion is explained here: " \
69               "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \
70               " **** READ THIS WEB PAGE !!! ****");
71 #else
72   #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \
73     eigen_assert((reinterpret_cast<size_t>(array) & sizemask) == 0 \
74               && "this assertion is explained here: " \
75               "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \
76               " **** READ THIS WEB PAGE !!! ****");
77 #endif
78 
79 template <typename T, int Size, int MatrixOrArrayOptions>
80 struct plain_array<T, Size, MatrixOrArrayOptions, 16>
81 {
82   EIGEN_USER_ALIGN16 T array[Size];
83 
84   plain_array()
85   {
86     EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(0xf);
87     check_static_allocation_size<T,Size>();
88   }
89 
90   plain_array(constructor_without_unaligned_array_assert)
91   {
92     check_static_allocation_size<T,Size>();
93   }
94 };
95 
96 template <typename T, int MatrixOrArrayOptions, int Alignment>
97 struct plain_array<T, 0, MatrixOrArrayOptions, Alignment>
98 {
99   EIGEN_USER_ALIGN16 T array[1];
100   plain_array() {}
101   plain_array(constructor_without_unaligned_array_assert) {}
102 };
103 
104 } // end namespace internal
105 
106 /** \internal
107   *
108   * \class DenseStorage
109   * \ingroup Core_Module
110   *
111   * \brief Stores the data of a matrix
112   *
113   * This class stores the data of fixed-size, dynamic-size or mixed matrices
114   * in a way as compact as possible.
115   *
116   * \sa Matrix
117   */
118 template<typename T, int Size, int _Rows, int _Cols, int _Options> class DenseStorage;
119 
120 // purely fixed-size matrix
121 template<typename T, int Size, int _Rows, int _Cols, int _Options> class DenseStorage
122 {
123     internal::plain_array<T,Size,_Options> m_data;
124   public:
125     inline DenseStorage() {}
126     inline DenseStorage(internal::constructor_without_unaligned_array_assert)
127       : m_data(internal::constructor_without_unaligned_array_assert()) {}
128     inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {}
129     inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); }
130     static inline DenseIndex rows(void) {return _Rows;}
131     static inline DenseIndex cols(void) {return _Cols;}
132     inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {}
133     inline void resize(DenseIndex,DenseIndex,DenseIndex) {}
134     inline const T *data() const { return m_data.array; }
135     inline T *data() { return m_data.array; }
136 };
137 
138 // null matrix
139 template<typename T, int _Rows, int _Cols, int _Options> class DenseStorage<T, 0, _Rows, _Cols, _Options>
140 {
141   public:
142     inline DenseStorage() {}
143     inline DenseStorage(internal::constructor_without_unaligned_array_assert) {}
144     inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {}
145     inline void swap(DenseStorage& ) {}
146     static inline DenseIndex rows(void) {return _Rows;}
147     static inline DenseIndex cols(void) {return _Cols;}
148     inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {}
149     inline void resize(DenseIndex,DenseIndex,DenseIndex) {}
150     inline const T *data() const { return 0; }
151     inline T *data() { return 0; }
152 };
153 
154 // more specializations for null matrices; these are necessary to resolve ambiguities
155 template<typename T, int _Options> class DenseStorage<T, 0, Dynamic, Dynamic, _Options>
156 : public DenseStorage<T, 0, 0, 0, _Options> { };
157 
158 template<typename T, int _Rows, int _Options> class DenseStorage<T, 0, _Rows, Dynamic, _Options>
159 : public DenseStorage<T, 0, 0, 0, _Options> { };
160 
161 template<typename T, int _Cols, int _Options> class DenseStorage<T, 0, Dynamic, _Cols, _Options>
162 : public DenseStorage<T, 0, 0, 0, _Options> { };
163 
164 // dynamic-size matrix with fixed-size storage
165 template<typename T, int Size, int _Options> class DenseStorage<T, Size, Dynamic, Dynamic, _Options>
166 {
167     internal::plain_array<T,Size,_Options> m_data;
168     DenseIndex m_rows;
169     DenseIndex m_cols;
170   public:
171     inline DenseStorage() : m_rows(0), m_cols(0) {}
172     inline DenseStorage(internal::constructor_without_unaligned_array_assert)
173       : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {}
174     inline DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) : m_rows(nbRows), m_cols(nbCols) {}
175     inline void swap(DenseStorage& other)
176     { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); }
177     inline DenseIndex rows() const {return m_rows;}
178     inline DenseIndex cols() const {return m_cols;}
179     inline void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; }
180     inline void resize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; }
181     inline const T *data() const { return m_data.array; }
182     inline T *data() { return m_data.array; }
183 };
184 
185 // dynamic-size matrix with fixed-size storage and fixed width
186 template<typename T, int Size, int _Cols, int _Options> class DenseStorage<T, Size, Dynamic, _Cols, _Options>
187 {
188     internal::plain_array<T,Size,_Options> m_data;
189     DenseIndex m_rows;
190   public:
191     inline DenseStorage() : m_rows(0) {}
192     inline DenseStorage(internal::constructor_without_unaligned_array_assert)
193       : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {}
194     inline DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex) : m_rows(nbRows) {}
195     inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); }
196     inline DenseIndex rows(void) const {return m_rows;}
197     inline DenseIndex cols(void) const {return _Cols;}
198     inline void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; }
199     inline void resize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; }
200     inline const T *data() const { return m_data.array; }
201     inline T *data() { return m_data.array; }
202 };
203 
204 // dynamic-size matrix with fixed-size storage and fixed height
205 template<typename T, int Size, int _Rows, int _Options> class DenseStorage<T, Size, _Rows, Dynamic, _Options>
206 {
207     internal::plain_array<T,Size,_Options> m_data;
208     DenseIndex m_cols;
209   public:
210     inline DenseStorage() : m_cols(0) {}
211     inline DenseStorage(internal::constructor_without_unaligned_array_assert)
212       : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {}
213     inline DenseStorage(DenseIndex, DenseIndex, DenseIndex nbCols) : m_cols(nbCols) {}
214     inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); }
215     inline DenseIndex rows(void) const {return _Rows;}
216     inline DenseIndex cols(void) const {return m_cols;}
217     inline void conservativeResize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; }
218     inline void resize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; }
219     inline const T *data() const { return m_data.array; }
220     inline T *data() { return m_data.array; }
221 };
222 
223 // purely dynamic matrix.
224 template<typename T, int _Options> class DenseStorage<T, Dynamic, Dynamic, Dynamic, _Options>
225 {
226     T *m_data;
227     DenseIndex m_rows;
228     DenseIndex m_cols;
229   public:
230     inline DenseStorage() : m_data(0), m_rows(0), m_cols(0) {}
231     inline DenseStorage(internal::constructor_without_unaligned_array_assert)
232        : m_data(0), m_rows(0), m_cols(0) {}
233     inline DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols)
234       : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_rows(nbRows), m_cols(nbCols)
235     { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN }
236     inline ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, m_rows*m_cols); }
237     inline void swap(DenseStorage& other)
238     { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); }
239     inline DenseIndex rows(void) const {return m_rows;}
240     inline DenseIndex cols(void) const {return m_cols;}
241     inline void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols)
242     {
243       m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, m_rows*m_cols);
244       m_rows = nbRows;
245       m_cols = nbCols;
246     }
247     void resize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols)
248     {
249       if(size != m_rows*m_cols)
250       {
251         internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, m_rows*m_cols);
252         if (size)
253           m_data = internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size);
254         else
255           m_data = 0;
256         EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN
257       }
258       m_rows = nbRows;
259       m_cols = nbCols;
260     }
261     inline const T *data() const { return m_data; }
262     inline T *data() { return m_data; }
263 };
264 
265 // matrix with dynamic width and fixed height (so that matrix has dynamic size).
266 template<typename T, int _Rows, int _Options> class DenseStorage<T, Dynamic, _Rows, Dynamic, _Options>
267 {
268     T *m_data;
269     DenseIndex m_cols;
270   public:
271     inline DenseStorage() : m_data(0), m_cols(0) {}
272     inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {}
273     inline DenseStorage(DenseIndex size, DenseIndex, DenseIndex nbCols) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_cols(nbCols)
274     { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN }
275     inline ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Rows*m_cols); }
276     inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); }
277     static inline DenseIndex rows(void) {return _Rows;}
278     inline DenseIndex cols(void) const {return m_cols;}
279     inline void conservativeResize(DenseIndex size, DenseIndex, DenseIndex nbCols)
280     {
281       m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, _Rows*m_cols);
282       m_cols = nbCols;
283     }
284     EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex, DenseIndex nbCols)
285     {
286       if(size != _Rows*m_cols)
287       {
288         internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Rows*m_cols);
289         if (size)
290           m_data = internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size);
291         else
292           m_data = 0;
293         EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN
294       }
295       m_cols = nbCols;
296     }
297     inline const T *data() const { return m_data; }
298     inline T *data() { return m_data; }
299 };
300 
301 // matrix with dynamic height and fixed width (so that matrix has dynamic size).
302 template<typename T, int _Cols, int _Options> class DenseStorage<T, Dynamic, Dynamic, _Cols, _Options>
303 {
304     T *m_data;
305     DenseIndex m_rows;
306   public:
307     inline DenseStorage() : m_data(0), m_rows(0) {}
308     inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {}
309     inline DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_rows(nbRows)
310     { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN }
311     inline ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Cols*m_rows); }
312     inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); }
313     inline DenseIndex rows(void) const {return m_rows;}
314     static inline DenseIndex cols(void) {return _Cols;}
315     inline void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex)
316     {
317       m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, m_rows*_Cols);
318       m_rows = nbRows;
319     }
320     EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex nbRows, DenseIndex)
321     {
322       if(size != m_rows*_Cols)
323       {
324         internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Cols*m_rows);
325         if (size)
326           m_data = internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size);
327         else
328           m_data = 0;
329         EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN
330       }
331       m_rows = nbRows;
332     }
333     inline const T *data() const { return m_data; }
334     inline T *data() { return m_data; }
335 };
336 
337 } // end namespace Eigen
338 
339 #endif // EIGEN_MATRIX_H
340