1 /** \file
2 * \brief Declaration and implementation of class Array2D which implements
3 * dynamic two dimensional arrays.
4 *
5 * \author Carsten Gutwenger
6 *
7 * \par License:
8 * This file is part of the Open Graph Drawing Framework (OGDF).
9 *
10 * \par
11 * Copyright (C)<br>
12 * See README.md in the OGDF root directory for details.
13 *
14 * \par
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * Version 2 or 3 as published by the Free Software Foundation;
18 * see the file LICENSE.txt included in the packaging of this file
19 * for details.
20 *
21 * \par
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * \par
28 * You should have received a copy of the GNU General Public
29 * License along with this program; if not, see
30 * http://www.gnu.org/copyleft/gpl.html
31 */
32
33 #pragma once
34
35 #include <ogdf/basic/exceptions.h>
36
37 namespace ogdf {
38
39
40 //! The parameterized class Array2D implements dynamic two-dimensional arrays.
41 /**
42 * @ingroup containers
43 *
44 * @tparam E denotes the element type.
45 */
46 template<class E> class Array2D
47 {
48 public:
49 // constructors
50
51 //! Creates a two-dimensional array with empty index set.
Array2D()52 Array2D() { construct(0,-1,0,-1); }
53
54 //! Creates a two-dimensional array with index set [\p a, ..., \p b]*[\p c, ..., \p d].
Array2D(int a,int b,int c,int d)55 Array2D(int a, int b, int c, int d) {
56 construct(a,b,c,d); initialize();
57 }
58
59 //! Creates a two-dimensional array with index set [\p a, ..., \p b]*[\p c, ..., \p d] and initailizes all elements with \p x.
Array2D(int a,int b,int c,int d,const E & x)60 Array2D(int a, int b, int c, int d, const E &x) {
61 construct(a,b,c,d); initialize(x);
62 }
63
64 //! Creates a two-dimensional array that is a copy of \p A.
Array2D(const Array2D<E> & A)65 Array2D(const Array2D<E> &A) {
66 copy(A);
67 }
68
69 //! Creates a two-dimensional array containing the elements of \p A (move semantics).
70 /**
71 * The array \p A is empty afterwards.
72 */
Array2D(Array2D<E> && A)73 Array2D(Array2D<E> &&A)
74 : m_vpStart(A.m_vpStart), m_lenDim2(A.m_lenDim2), m_pStart(A.m_pStart), m_pStop(A.m_pStop),
75 m_a(A.m_a), m_b(A.m_b), m_c(A.m_c), m_d(A.m_d)
76 {
77 A.construct(0,-1,0,-1);
78 }
79
80 //! Destructor
~Array2D()81 ~Array2D() {
82 deconstruct();
83 }
84
85 //! Returns the minimal array index in dimension 1.
low1()86 int low1() const { return m_a; }
87
88 //! Returns the maximal array index in dimension 1.
high1()89 int high1() const { return m_b; }
90
91 //! Returns the minimal array index in dimension 2.
low2()92 int low2() const { return m_c; }
93
94 //! Returns the maximal array index in dimension 2.
high2()95 int high2() const { return m_d; }
96
97 //! Returns the size (number of elements) of the array.
size()98 int size() const { return size1() * size2(); }
99
100 //! Returns the length of the index interval (number of entries) in dimension 1.
size1()101 int size1() const { return m_b - m_a + 1; }
102
103 //! Returns the length of the index interval (number of entries) in dimension 2.
size2()104 int size2() const { return m_lenDim2; }
105
106 //! Returns the determinant of the matrix
107 /*! \note use only for square matrices and floating point values */
108 float det() const;
109
110 //! Returns a reference to the element with index (\p i,\p j).
operator()111 const E &operator()(int i, int j) const {
112 OGDF_ASSERT(m_a <= i);
113 OGDF_ASSERT(i <= m_b);
114 OGDF_ASSERT(m_c <= j);
115 OGDF_ASSERT(j <= m_d);
116 return m_vpStart[size_t(i-m_a)*m_lenDim2+j];
117 }
118
119 //! Returns a reference to the element with index (\p i,\p j).
operator()120 E &operator()(int i, int j) {
121 OGDF_ASSERT(m_a <= i);
122 OGDF_ASSERT(i <= m_b);
123 OGDF_ASSERT(m_c <= j);
124 OGDF_ASSERT(j <= m_d);
125 return m_vpStart[size_t(i-m_a)*m_lenDim2+j];
126 }
127
128 //! Reinitializes the array to an array with empty index set.
init()129 void init() { init(0,-1,0,-1); }
130
131 //! Reinitializes the array to an array with index set [\p a, ..., \p b]*[\p c, ..., \p d].
init(int a,int b,int c,int d)132 void init(int a, int b, int c, int d) {
133 deconstruct();
134 construct(a,b,c,d);
135 initialize();
136 }
137
138 //! Reinitializes the array to an array with index set [\p a, ..., \p b]*[\p c, ..., \p d] and initializes all entries with \p x.
init(int a,int b,int c,int d,const E & x)139 void init(int a, int b, int c, int d, const E &x) {
140 deconstruct();
141 construct(a,b,c,d);
142 initialize(x);
143 }
144
145 //! Assignment operator.
146 Array2D<E> &operator=(const Array2D<E> &array2) {
147 deconstruct();
148 copy(array2);
149 return *this;
150 }
151
152 //! Assignment operator (move semantics).
153 /**
154 * Array \p A is empty afterwards.
155 */
156 Array2D<E> &operator=(Array2D<E> &&A) {
157 deconstruct();
158
159 m_vpStart = A.m_vpStart;
160 m_pStart = A.m_pStart;
161 m_pStop = A.m_pStop;
162 m_lenDim2 = A.m_lenDim2;
163 m_a = A.m_a;
164 m_b = A.m_b;
165 m_c = A.m_c;
166 m_d = A.m_d;
167
168 A.construct(0,-1,0,-1);
169 return *this;
170 }
171
172 //! Sets all elements to \p x.
fill(const E & x)173 void fill(const E &x) {
174 E *pDest = m_pStop;
175 while(pDest > m_pStart)
176 *--pDest = x;
177 }
178
179 private:
180 E *m_vpStart; //!< The virtual start of the array (address of A[0,0]).
181 int m_lenDim2; //!< The number of elements in dimension 2.
182 E *m_pStart; //!< The real start of the array (address of A[low1,low2]).
183 E *m_pStop; //!< Successor of last element (address of A[high1,high2+1]).
184
185 int m_a; //!< The lowest index in dimension 1.
186 int m_b; //!< The highest index in dimension 1.
187 int m_c; //!< The lowest index in dimension 2.
188 int m_d; //!< The highest index in dimension 2.
189
190 void construct(int a, int b, int c, int d);
191
192 void initialize();
193 void initialize(const E &x);
194
195 void deconstruct();
196
197 void copy(const Array2D<E> &array2);
198 };
199
200
201 //! Constructs the array with index set [\p a, ..., \p b]*[\p c, ..., \p d].
202 template<class E>
construct(int a,int b,int c,int d)203 void Array2D<E>::construct(int a, int b, int c, int d)
204 {
205 m_a = a;
206 m_b = b;
207 m_c = c;
208 m_d = d;
209
210 size_t lenDim1 = b-a+1;
211 m_lenDim2 = d-c+1;
212
213 if (lenDim1 < 1 || m_lenDim2 < 1) {
214 m_pStart = m_vpStart = m_pStop = nullptr;
215
216 } else {
217 size_t len = lenDim1*m_lenDim2;
218 m_pStart = static_cast<E *>( malloc(len*sizeof(E)) );
219 if (m_pStart == nullptr)
220 OGDF_THROW(InsufficientMemoryException);
221
222 m_vpStart = m_pStart - c;
223 m_pStop = m_pStart + len;
224 }
225 }
226
227
228 //! Initializes the array with default constructor of \a E.
229 template<class E>
initialize()230 void Array2D<E>::initialize()
231 {
232 E *pDest = m_pStart;
233 try {
234 for (; pDest < m_pStop; pDest++)
235 new(pDest) E;
236 } catch (...) {
237 while(--pDest >= m_pStart)
238 pDest->~E();
239 free(m_pStart);
240 throw;
241 }
242 }
243
244
245 //! Initializes the array with \p x.
246 template<class E>
initialize(const E & x)247 void Array2D<E>::initialize(const E &x)
248 {
249 E *pDest = m_pStart;
250 try {
251 for (; pDest < m_pStop; pDest++)
252 new(pDest) E(x);
253 } catch (...) {
254 while(--pDest >= m_pStart)
255 pDest->~E();
256 free(m_pStart);
257 throw;
258 }
259 }
260
261
262 //! Call destructor of all elements.
263 template<class E>
deconstruct()264 void Array2D<E>::deconstruct()
265 {
266 if (!std::is_trivially_destructible<E>::value) {
267 for (E *pDest = m_pStart; pDest < m_pStop; pDest++)
268 pDest->~E();
269 }
270 free(m_pStart);
271 }
272
273 //! Copy \p array2.
274 template<class E>
copy(const Array2D<E> & array2)275 void Array2D<E>::copy(const Array2D<E> &array2)
276 {
277 construct(array2.m_a, array2.m_b, array2.m_c, array2.m_d);
278
279 if (m_pStart != 0) {
280 E *pSrc = array2.m_pStop;
281 E *pDest = m_pStop;
282 while(pDest > m_pStart)
283 new (--pDest) E(*--pSrc);
284 }
285 }
286
287
288 //! Computes the determinant via row expansion.
289 template<class E>
det()290 float Array2D<E>::det() const
291 {
292 // matrix must be quadratic
293 OGDF_ASSERT(size1() == size2());
294
295 int a = m_a;
296 int b = m_b;
297 int c = m_c;
298 int d = m_d;
299 int n = m_lenDim2;
300
301 int i, j;
302 int column;
303
304 float determinant = 0.0;
305
306 switch(n) {
307 case 0:
308 break;
309 case 1:
310 determinant = (float)((*this)(a, c));
311 break;
312 case 2:
313 determinant = (float)((*this)(a, c) * (*this)(b, d) - (*this)(a, d) * (*this)(b, c));
314 break;
315
316 // Expanding along the first row (Laplace's Formula)
317 default:
318 Array2D<E> remMatrix(0, n-2, 0, n-2); // the remaining matrix
319 for(column = c; column <= d; column++) {
320 int rem_i = 0;
321 int rem_j = 0;
322 for(i = a; i <= b; i++) {
323 for(j = c; j <= d; j++) {
324 if(i != a && j != column) {
325 remMatrix(rem_i, rem_j) = (*this)(i, j);
326 if(rem_j < n-2) {
327 rem_j++;
328 }
329 else {
330 rem_i++;
331 rem_j = 0;
332 }
333 }
334 }
335 }
336 determinant += pow(-1.0,(a+column)) * (*this)(a,column) * remMatrix.det();
337 }
338 }
339
340 return determinant;
341 }
342
343 }
344