0030478: Foundation Classes, NCollection_Array2 - provide Resize/Move methods consist...
[occt.git] / src / NCollection / NCollection_Array2.hxx
1 // Created on: 2002-04-15
2 // Created by: Alexander Kartomin (akm)
3 // Copyright (c) 2002-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #ifndef NCollection_Array2_HeaderFile
17 #define NCollection_Array2_HeaderFile
18
19 #include <Standard_DimensionMismatch.hxx>
20 #include <Standard_OutOfMemory.hxx>
21 #include <Standard_OutOfRange.hxx>
22
23 #include <NCollection_DefineAlloc.hxx>
24
25 // *********************************************** Template for Array2 class
26 /**
27 * Purpose:   The class Array2 represents bi-dimensional arrays 
28 *            of fixed size known at run time. 
29 *            The ranges of indices are user defined.
30 *
31 *            Class allocates one 1D array storing full data (all Rows and Columns)
32 *            and extra 1D array storing pointers to each Row.
33 *
34 * Warning:   Programs clients of such class must be independent
35 *            of the range of the first element. Then, a C++ for
36 *            loop must be written like this
37 *            
38 *            for (i = A.LowerRow(); i <= A.UpperRow(); i++)
39 *              for (j = A.LowerCol(); j <= A.UpperCol(); j++)
40 */            
41 template <class TheItemType>
42 class NCollection_Array2
43 {
44 public:
45   //! STL-compliant typedef for value type
46   typedef TheItemType value_type;
47
48 public:
49   // **************** Implementation of the Iterator interface.
50   class Iterator
51   {
52   public:
53     //! Empty constructor - for later Init
54     Iterator (void) :
55       myCurrent (0),
56       mySize    (0),
57       myArray   (NULL) {}
58     //! Constructor with initialisation
59     Iterator  (const NCollection_Array2& theArray) :
60       myCurrent (0),
61       mySize    (theArray.Length()),
62       myArray   ((NCollection_Array2 *) &theArray) {}
63     //! Initialisation
64     void Init (const NCollection_Array2& theArray)
65     { 
66       myCurrent = 0;
67       mySize    = theArray.Length();
68       myArray   = (NCollection_Array2 *) &theArray; 
69     }
70     //! Check end
71     Standard_Boolean More (void) const
72     { return (myCurrent < mySize); }
73     //! Make step
74     void Next (void)
75     { myCurrent++; }
76     //! Constant value access
77     const TheItemType& Value (void) const
78     { return myArray->myStart[myCurrent]; }
79     //! Variable value access
80     TheItemType& ChangeValue (void) const
81     { return myArray->myStart[myCurrent]; }
82   private:
83     Standard_Integer    myCurrent;  //!< Index of the current item
84     Standard_Integer    mySize;     //!< Total amount of items
85     NCollection_Array2* myArray;    //!< Pointer to the array being iterated
86   }; // End of nested class Iterator
87
88  public:
89   // ---------- PUBLIC METHODS ------------
90
91   //! Empty constructor; should be used with caution.
92   //! @sa methods Resize() and Move().
93   NCollection_Array2()
94   : myLowerRow (1),
95     myUpperRow (0),
96     myLowerCol (1),
97     myUpperCol (0),
98     myData  (NULL),
99     myStart (NULL),
100     myDeletable(false)
101   {
102     //
103   }
104
105   //! Constructor
106   NCollection_Array2(const Standard_Integer theRowLower,
107                      const Standard_Integer theRowUpper,
108                      const Standard_Integer theColLower,
109                      const Standard_Integer theColUpper) :
110     myLowerRow                                  (theRowLower),
111     myUpperRow                                  (theRowUpper),
112     myLowerCol                                  (theColLower),
113     myUpperCol                                  (theColUpper),
114     myDeletable                                 (Standard_True)
115   { Allocate(); }
116
117   //! Copy constructor 
118   NCollection_Array2 (const NCollection_Array2& theOther) :
119     myLowerRow                                  (theOther.LowerRow()),
120     myUpperRow                                  (theOther.UpperRow()),
121     myLowerCol                                  (theOther.LowerCol()),
122     myUpperCol                                  (theOther.UpperCol()),
123     myDeletable                                 (Standard_True)
124   {
125     Allocate();
126     *this = theOther;
127   }
128
129 #ifndef OCCT_NO_RVALUE_REFERENCE
130   //! Move constructor
131   NCollection_Array2 (NCollection_Array2&& theOther)
132   : myLowerRow (theOther.myLowerRow),
133     myUpperRow (theOther.myUpperRow),
134     myLowerCol (theOther.myLowerRow),
135     myUpperCol (theOther.myUpperCol),
136     myData     (theOther.myData),
137     myStart    (theOther.myStart),
138     myDeletable(theOther.myDeletable)
139   {
140     theOther.myStart = NULL;
141     theOther.myData  = NULL;
142     theOther.myDeletable = false;
143   }
144 #endif
145
146   //! C array-based constructor
147   NCollection_Array2(const TheItemType&     theBegin,
148                      const Standard_Integer theRowLower,
149                      const Standard_Integer theRowUpper,
150                      const Standard_Integer theColLower,
151                      const Standard_Integer theColUpper) :
152     myLowerRow                                  (theRowLower),
153     myUpperRow                                  (theRowUpper),
154     myLowerCol                                  (theColLower),
155     myUpperCol                                  (theColUpper),
156     myDeletable                                 (Standard_False)
157   {
158     myStart = (TheItemType *) &theBegin;
159     Allocate();
160   }
161
162   //! Initialise the values
163   void Init (const TheItemType& theValue) 
164   {
165     TheItemType *pCur, *pEnd=myStart+Size();
166     for(pCur = myStart; pCur<pEnd; pCur++)
167       *pCur = theValue;
168   }
169
170   //! Size (number of items)
171   Standard_Integer Size (void) const
172   { return Length(); }
173   //! Length (number of items)
174   Standard_Integer Length (void) const
175   { return NbRows() * NbColumns(); }
176
177   //! Returns number of rows
178   Standard_Integer NbRows() const { return myUpperRow - myLowerRow + 1; }
179
180   //! Returns number of columns
181   Standard_Integer NbColumns() const { return myUpperCol - myLowerCol + 1; }
182
183   //! Returns length of the row, i.e. number of columns
184   Standard_Integer RowLength() const { return NbColumns(); }
185
186   //! Returns length of the column, i.e. number of rows
187   Standard_Integer ColLength() const { return NbRows(); }
188
189   //! LowerRow
190   Standard_Integer LowerRow (void) const
191   { return myLowerRow; }
192   //! UpperRow
193   Standard_Integer UpperRow (void) const
194   { return myUpperRow; }
195   //! LowerCol
196   Standard_Integer LowerCol (void) const
197   { return myLowerCol; }
198   //! UpperCol
199   Standard_Integer UpperCol (void) const
200   { return myUpperCol; }
201
202   //! myDeletable flag
203   Standard_Boolean IsDeletable (void) const
204   { return myDeletable; }
205
206   //! Assignment
207   NCollection_Array2& Assign (const NCollection_Array2& theOther)
208   { 
209     if (&theOther == this)
210       return *this;
211     Standard_DimensionMismatch_Raise_if (Length() != theOther.Length(), "NCollection_Array2::operator=");
212     TheItemType * pMyItem  = myStart;
213     TheItemType * pItem    = theOther.myStart;
214     const Standard_Integer iSize = Length();
215     for (Standard_Integer i=0; i < iSize; i++, pItem++, pMyItem++)
216       *pMyItem = *pItem;
217     return *this; 
218   }
219
220   //! Move assignment.
221   //! This array will borrow all the data from theOther.
222   //! The moved object will be left unitialized and should not be used anymore.
223   NCollection_Array2& Move (NCollection_Array2& theOther)
224   {
225     if (&theOther == this)
226     {
227       return *this;
228     }
229
230     if (myDeletable)
231     {
232       delete[] myStart;
233     }
234     if (myData != NULL)
235     {
236       delete[] &(myData[myLowerRow]);
237     }
238
239     myLowerRow  = theOther.myLowerRow;
240     myUpperRow  = theOther.myUpperRow;
241     myLowerCol  = theOther.myLowerRow;
242     myUpperCol  = theOther.myUpperCol;
243     myData      = theOther.myData;
244     myStart     = theOther.myStart;
245     myDeletable = theOther.myDeletable;
246
247     theOther.myStart = NULL;
248     theOther.myData  = NULL;
249     theOther.myDeletable = Standard_False;
250     return *this;
251   }
252
253   //! Assignment operator
254   NCollection_Array2& operator= (const NCollection_Array2& theOther)
255   { 
256     return Assign (theOther);
257   }
258
259 #ifndef OCCT_NO_RVALUE_REFERENCE
260   //! Move assignment operator; @sa Move()
261   NCollection_Array2& operator= (NCollection_Array2&& theOther)
262   {
263     return Move (theOther);
264   }
265 #endif
266
267   //! Constant value access
268   const TheItemType& Value (const Standard_Integer theRow,
269                             const Standard_Integer theCol) const
270   {
271     Standard_OutOfRange_Raise_if (theRow < myLowerRow || theRow > myUpperRow ||
272                                   theCol < myLowerCol || theCol > myUpperCol, "NCollection_Array2::Value");
273     return myData[theRow][theCol];
274   }
275
276   //! operator() - alias to ChangeValue
277   const TheItemType& operator() (const Standard_Integer theRow,
278                                  const Standard_Integer theCol) const
279   { return Value (theRow,theCol); }
280
281   //! Variable value access
282   TheItemType& ChangeValue (const Standard_Integer theRow,
283                             const Standard_Integer theCol)
284   {
285     Standard_OutOfRange_Raise_if (theRow < myLowerRow || theRow > myUpperRow ||
286                                   theCol < myLowerCol || theCol > myUpperCol, "NCollection_Array2::ChangeValue");
287     return myData[theRow][theCol];
288   }
289
290   //! operator() - alias to ChangeValue
291   TheItemType& operator() (const Standard_Integer theRow,
292                            const Standard_Integer theCol)
293   { return ChangeValue (theRow,theCol); }
294
295   //! SetValue
296   void SetValue (const Standard_Integer theRow,
297                  const Standard_Integer theCol,
298                  const TheItemType&     theItem)
299   {
300     Standard_OutOfRange_Raise_if (theRow < myLowerRow || theRow > myUpperRow ||
301                                   theCol < myLowerCol || theCol > myUpperCol, "NCollection_Array2::SetValue");
302     myData[theRow][theCol] = theItem;
303   }
304
305   //! Resizes the array to specified bounds.
306   //! No re-allocation will be done if length of array does not change,
307   //! but existing values will not be discarded if theToCopyData set to FALSE.
308   //! @param theRowLower new lower Row of array
309   //! @param theRowUpper new upper Row of array
310   //! @param theColLower new lower Column of array
311   //! @param theColUpper new upper Column of array
312   //! @param theToCopyData flag to copy existing data into new array
313   void Resize (Standard_Integer theRowLower,
314                Standard_Integer theRowUpper,
315                Standard_Integer theColLower,
316                Standard_Integer theColUpper,
317                Standard_Boolean theToCopyData)
318   {
319     Standard_RangeError_Raise_if (theRowUpper < theRowLower
320                                || theColUpper < theColLower, "NCollection_Array2::Resize");
321     const Standard_Integer anOldNbRows  = NbRows();
322     const Standard_Integer anOldNbCols  = NbColumns();
323     const Standard_Integer aLowerRowOld = myLowerRow;
324     const Standard_Integer aLowerColOld = myLowerCol;
325     const Standard_Integer aNewNbRows   = theRowUpper - theRowLower + 1;
326     const Standard_Integer aNewNbCols   = theColUpper - theColLower + 1;
327
328     TheItemType*  aStartOld = myStart;
329     TheItemType** aTableOld = myData != NULL ? myData + aLowerRowOld : NULL;
330     myLowerRow = theRowLower;
331     myUpperRow = theRowUpper;
332     myLowerCol = theColLower;
333     myUpperCol = theColUpper;
334     if (aNewNbRows == anOldNbRows
335      && aNewNbCols == anOldNbCols)
336     {
337       if (myLowerCol != aLowerColOld)
338       {
339         fillIndexTable (aTableOld);
340       }
341       myData = aTableOld - myLowerRow;
342       return;
343     }
344
345     if (myDeletable
346     && !theToCopyData)
347     {
348       delete[] aStartOld;
349     }
350     delete[] aTableOld;
351
352     Allocate();
353     if (!theToCopyData)
354     {
355       myDeletable = Standard_True;
356       return;
357     }
358
359     const Standard_Integer aNbRowsToCopy = Min (anOldNbRows, aNewNbRows);
360     const Standard_Integer aNbColsToCopy = Min (anOldNbCols, aNewNbCols);
361     for (Standard_Integer aRowIter = 0; aRowIter < aNbRowsToCopy; ++aRowIter)
362     {
363       for (Standard_Integer aColIter = 0; aColIter < aNbColsToCopy; ++aColIter)
364       {
365         myStart[size_t(aRowIter) * size_t(aNewNbCols) + size_t(aColIter)] = aStartOld[size_t(aRowIter) * size_t(anOldNbCols) + size_t(aColIter)];
366       }
367     }
368
369     if (myDeletable)
370     {
371       delete[] aStartOld;
372     }
373     myDeletable = Standard_True;
374   }
375
376   //! Destructor - releases the memory
377   ~NCollection_Array2 (void)
378   { 
379     if (myDeletable) delete [] myStart;
380     if (myData != NULL)
381     {
382       delete[] &(myData[myLowerRow]);
383     }
384   }
385
386  private:
387   // ----------- PRIVATE METHODS -----------
388
389   //! Allocate memory for the array, set up indirection table
390   void Allocate (void)
391   {
392     const Standard_Integer aNbRows = NbRows();
393     const Standard_Integer aNbCols = NbColumns();
394     Standard_RangeError_Raise_if (aNbRows <= 0  || aNbCols <= 0, "NCollection_Array2::Allocate");
395     if (myDeletable)
396     {
397       // allocation of the data in the array
398       myStart = new TheItemType[size_t(aNbRows) * size_t(aNbCols)];
399       Standard_OutOfMemory_Raise_if (!myStart, "NCollection_Array2 : Allocation failed");
400     }
401     // else myStart is set to the beginning of the given array
402
403     TheItemType** pTable = new TheItemType* [aNbRows];
404     Standard_OutOfMemory_Raise_if (!pTable, "NCollection_Array2 : Allocation failed");
405     fillIndexTable (pTable);
406   }
407
408   //! Fill index table for accessing array elements.
409   void fillIndexTable (TheItemType** theTable)
410   {
411     // Items of table point to the 0th items in the rows of the array
412     TheItemType* aRow = myStart - myLowerCol;
413     const Standard_Integer aNbRows = NbRows();
414     const Standard_Size    aNbCols = NbColumns();
415     for (Standard_Integer aRowIter = 0; aRowIter < aNbRows; ++aRowIter)
416     {
417       theTable[aRowIter] = aRow;
418       aRow += aNbCols;
419     }
420
421     // Set myData to the 0th row pointer of the table
422     myData = theTable - myLowerRow;
423   }
424
425  protected:
426   // ---------- PROTECTED FIELDS -----------
427   Standard_Integer myLowerRow;
428   Standard_Integer myUpperRow;
429   Standard_Integer myLowerCol;
430   Standard_Integer myUpperCol;
431
432   TheItemType**    myData;      //!< Pointer to the row pointers table
433   TheItemType*     myStart;     //!< Pointer to the memory array
434   Standard_Boolean myDeletable; //!< Flag showing who allocated the array
435
436   // ----------- FRIEND CLASSES ------------
437  friend class Iterator;
438
439 };
440
441 #endif