1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the class library                   */
4    	/*       SoPlex --- the Sequential object-oriented simPlex.                  */
5    	/*                                                                           */
6    	/*    Copyright (C) 1996-2022 Konrad-Zuse-Zentrum                            */
7    	/*                            fuer Informationstechnik Berlin                */
8    	/*                                                                           */
9    	/*  SoPlex is distributed under the terms of the ZIB Academic Licence.       */
10   	/*                                                                           */
11   	/*  You should have received a copy of the ZIB Academic License              */
12   	/*  along with SoPlex; see the file COPYING. If not email to soplex@zib.de.  */
13   	/*                                                                           */
14   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15   	
16   	/**@file  dataarray.h
17   	 * @brief Save arrays of data objects.
18   	 */
19   	#ifndef _DATAARRAY_H_
20   	#define _DATAARRAY_H_
21   	
22   	#include <assert.h>
23   	#include <stddef.h>
24   	#include <string.h>
25   	#include <iostream>
26   	#include <type_traits>
27   	
28   	#include "soplex/spxdefines.h"
29   	#include "soplex/spxalloc.h"
30   	#include "soplex/spxid.h"
31   	
32   	namespace soplex
33   	{
34   	/**@brief   Safe arrays of data objects.
35   	   @ingroup Elementary
36   	
37   	   Class DataArray provides safe arrays of \ref DataObjects. For general
38   	   C++ objects (in contrast to data objects) class Array is provided which
39   	   manages memory in a C++ compliant way.
40   	
41   	   The elements of an instance of DataArray can be accessed just like
42   	   ordinary C++ array elements by means of the index operator[](). Safety is
43   	   provided by
44   	
45   	    - automatic memory management in constructor and destructor
46   	      preventing memory leaks
47   	    - checking of array bounds when accessing elements with the
48   	      indexing operator[]() (only when compiled without \c -DNDEBUG).
49   	
50   	   Moreover, #DataArray%s may easily be extended by #insert%ing or #append%ing
51   	   elements to the DataArray or shrunken by \ref remove() "removing" elements.
52   	   Method reSize(int n) resets the DataArray%s length to \p n thereby possibly
53   	   appending elements or truncating the DataArray to the required size.
54   	
55   	   A DataArray may be used as arguments for standard C functions requiring
56   	   pointers through the use of get_ptr() and get_const_ptr().
57   	
58   	   Internally, a DataArray object allocates a block of memory that fits up
59   	   to max() elements, only size() of them are used. This makes extension
60   	   and shrinking methods perform better.
61   	
62   	   @see Array, \ref DataObjects "Data Objects"
63   	*/
64   	template < class T >
65   	class DataArray
66   	{
67   	   static_assert(std::is_trivially_copyable<T>::value,
68   	                 "Only trivially copyable types are allowed with DataArray, since it does memcopy");
69   	private:
70   	   int thesize;           ///< number of used elements in array data
71   	   int themax;            ///< the length of array data and
72   	   T*  data;              ///< the array of elements
73   	
74   	protected:
75   	   /** When a DataArray is reSize()%d to more than max() elements, the
76   	       new value for max() is not just set to the new size but rather to
77   	       \p memFactor * \p size. This makes #reSize%ing perform better in codes
78   	       where a DataArray is extended often by a small number of elements
79   	       only.
80   	    */
81   	   Real memFactor;     ///< memory extension factor.
82   	
83   	public:
84   	
85   	   /// reference \p n 'th element.
86   	   T& operator[](int n)
87   	   {
88   	      assert(n >= 0);
89   	      assert(n < thesize);
90   	      return data[n];
91   	   }
92   	   /// reference \p n 'th const element.
93   	   const T& operator[](int n) const
94   	   {
95   	      assert(n >= 0);
96   	      assert(n < thesize);
97   	      return data[n];
98   	   }
99   	
100  	   /// reference last element.
101  	   T& last()
102  	   {
103  	      assert(thesize > 0);
104  	      return data[thesize - 1];
105  	   }
106  	   /// reference last const element.
107  	   const T& last() const
108  	   {
109  	      assert(thesize > 0);
110  	      return data[thesize - 1];
111  	   }
112  	
113  	   /// get a C pointer to the data.
114  	   T* get_ptr()
115  	   {
116  	      return data;
117  	   }
118  	   /// get a const C pointer to the data.
119  	   const T* get_const_ptr() const
120  	   {
121  	      return data;
122  	   }
123  	
124  	   /// append element \p t.
125  	   void append(const T& t)
126  	   {
127  	      insert(thesize, 1, &t);
128  	   }
129  	   /// append \p n elements with value \p t.
130  	   void append(int n, const T& t)
131  	   {
132  	      insert(thesize, n, t);
133  	   }
134  	   /// append \p n elements from \p t.
135  	   void append(int n, const T t[])
136  	   {
137  	      insert(thesize, n, t);
138  	   }
139  	   /// append all elements from \p t.
140  	   void append(const DataArray<T>& t)
141  	   {
142  	      insert(thesize, t);
143  	   }
144  	
145  	   /// insert \p n uninitialized elements before \p i 'th element.
146  	   void insert(int i, int n)
147  	   {
148  	      int j = thesize;
149  	
150  	      assert(i >= 0);
151  	      assert(n >= 0);
152  	
153  	      reSize(thesize + n);
154  	
155  	      /// move \p n elements in memory from insert position \p i to the back
156  	      if(j > i)
157  	         memmove(&(data[i + n]), &(data[i]), (unsigned int)(j - i) * sizeof(T));
158  	   }
159  	
160  	   /// insert \p n elements with value \p t before \p i 'the element.
161  	   void insert(int i, int n, const T& t)
162  	   {
163  	      if(n > 0)
164  	      {
165  	         insert(i, n);
166  	
167  	         for(int j = 0; j < n; j++)
168  	            data[i + j] = t;
169  	      }
170  	   }
171  	
172  	   /// insert \p n elements from \p t before \p i 'the element.
173  	   void insert(int i, int n, const T t[])
174  	   {
175  	      if(n > 0)
176  	      {
177  	         insert(i, n);
178  	         memcpy(&(data[i]), t, (unsigned int) n * sizeof(T));
179  	      }
180  	   }
181  	
182  	   /// insert all elements from \p t before \p i 'th element.
183  	   void insert(int i, const DataArray<T>& t)
184  	   {
185  	      if(t.size())
186  	      {
187  	         insert(i, t.size());
188  	         memcpy(&(data[i]), t.data, (unsigned int)t.size() * sizeof(T));
189  	      }
190  	   }
191  	
192  	   /// remove \p m elements starting at \p n.
193  	   void remove(int n = 0, int m = 1)
194  	   {
195  	      assert(n < size() && n >= 0);
196  	
197  	      /* use memmove instead of memcopy because the destination and the source might overlap */
198  	      if(n + m < size())
199  	         memmove(&(data[n]), &(data[n + m]), (unsigned int)(size() - (n + m)) * sizeof(T));
200  	      else
201  	         m = size() - n;
202  	
203  	      thesize -= m;
204  	   }
205  	   /// remove \p m last elements.
206  	   void removeLast(int m = 1)
207  	   {
208  	      assert(m <= size() && m >= 0);
209  	      thesize -= m;
210  	   }
211  	   /// remove all elements.
212  	   void clear()
213  	   {
214  	      thesize = 0;
215  	   }
216  	
217  	   /// return nr. of elements.
218  	   int size() const
219  	   {
220  	      return thesize;
221  	   }
222  	
223  	   /// reset size to \p newsize.
224  	   /** Resizing a DataArray to less than the previous size, involves
225  	       discarding its last elements. Resizing to a larger value involves
226  	       adding uninitialized elements (similar to append()). If neccessary,
227  	       also memory will be reallocated.
228  	       @param newsize the new number of elements the array can hold.
229  	    */
230  	   void reSize(int newsize)
231  	   {
232  	      assert(memFactor >= 1);
233  	
234  	      if(newsize > themax)
235  	         reMax(int(memFactor * newsize), newsize);
236  	      else if(newsize < 0)
237  	         thesize = 0;
238  	      else
239  	         thesize = newsize;
240  	   }
241  	
242  	   /// return maximum number of elements.
243  	   /** Even though the DataArray currently holds no more than size()
244  	       elements, up to max() elements could be added without need to
245  	       reallocated free store.
246  	    */
247  	   int max() const
248  	   {
249  	      return themax;
250  	   }
251  	
252  	   /// reset maximum number of elements.
253  	   /** The value of max() is reset to \p newMax thereby setting size()
254  	       to \p newSize. However, if \p newSize has a value \c < \c 0 (as the
255  	       default argument does) size() remains unchanged and max() is set
256  	       to MIN(size(), newMax). Hence, calling reMax() without the
257  	       default arguments, will reduce the memory consumption to a minimum.
258  	       In no instance max() will be set to a value less than 1 (even if
259  	       specified).
260  	
261  	    */
262  	   void reMax(int newMax = 1, int newSize = -1)
263  	   {
264  	      if(newSize >= 0)
265  	         thesize = newSize;
266  	
267  	      if(newMax < newSize)
268  	         newMax = newSize;
269  	
270  	      if(newMax < 1)
271  	         newMax = 1;
272  	
273  	      if(newMax == themax)
274  	         return;
275  	
276  	      themax = newMax;
277  	
278  	      if(thesize <= 0)
279  	      {
280  	         /* no data needs to be copied so do a clean free and alloc */
281  	         spx_free(data);
282  	         spx_alloc(data, themax);
283  	      }
284  	      else
285  	         spx_realloc(data, themax);
286  	   }
287  	   /// assignment operator
288  	   DataArray& operator=(const DataArray& rhs)
289  	   {
290  	      if(this != &rhs)
291  	      {
292  	         reSize(rhs.size());
293  	         memcpy(data, rhs.data, (unsigned int) size() * sizeof(T));
294  	
295  	         assert(isConsistent());
296  	      }
297  	
298  	      return *this;
299  	   }
300  	
301  	   /// consistency check
302  	   bool isConsistent() const
303  	   {
304  	#ifdef ENABLE_CONSISTENCY_CHECKS
305  	
306  	      if((data == 0)
307  	            || (themax < 1)
308  	            || (themax < thesize)
309  	            || (thesize < 0)
310  	            || (memFactor < 1.0))
311  	         return MSGinconsistent("DataArray");
312  	
313  	#endif
314  	
315  	      return true;
316  	   }
317  	
318  	   /// copy constructor
319  	   DataArray(const DataArray& old)
320  	      : thesize(old.thesize)
321  	      , themax(old.themax)
322  	      , data(0)
323  	      , memFactor(old.memFactor)
324  	   {
325  	      spx_alloc(data, max());
326  	
327  	      assert(thesize >= 0);
328  	
329  	      if(thesize)
330  	         memcpy(data, old.data, (unsigned int)thesize * sizeof(T));
331  	
332  	      assert(isConsistent());
333  	   }
334  	
335  	   /// default constructor.
336  	   /** The constructor allocates an Array containing \p size uninitialized
337  	       elements. The internal array is allocated to have \p max nonzeros,
338  	       and the memory extension factor is set to \p fac.
339  	
340  	       @param p_size number of unitialised elements.
341  	       @param p_max  maximum number of elements the array can hold.
342  	       @param p_fac  value for memFactor.
343  	    */
344  	   explicit DataArray(int p_size = 0, int p_max = 0, Real p_fac = 1.2)
345  	      : data(0)
346  	      , memFactor(p_fac)
347  	   {
348  	      thesize = (p_size < 0) ? 0 : p_size;
349  	
350  	      if(p_max > thesize)
351  	         themax = p_max;
352  	      else
353  	         themax = (thesize == 0) ? 1 : thesize;
354  	
355  	      spx_alloc(data, themax);
356  	
357  	      assert(isConsistent());
358  	   }
359  	
360  	   /// destructor
361  	   ~DataArray()
362  	   {
363  	      if(data)
364  	         spx_free(data);
365  	   }
366  	};
367  	
368  	} // namespace soplex
369  	#endif // _DATAARRAY_H_
370