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 Iterator(void)54 Iterator (void) : 55 myCurrent (0), 56 mySize (0), 57 myArray (NULL) {} 58 //! Constructor with initialisation Iterator(const NCollection_Array2 & theArray)59 Iterator (const NCollection_Array2& theArray) : 60 myCurrent (0), 61 mySize (theArray.Length()), 62 myArray ((NCollection_Array2 *) &theArray) {} 63 //! Initialisation Init(const NCollection_Array2 & theArray)64 void Init (const NCollection_Array2& theArray) 65 { 66 myCurrent = 0; 67 mySize = theArray.Length(); 68 myArray = (NCollection_Array2 *) &theArray; 69 } 70 //! Check end More(void) const71 Standard_Boolean More (void) const 72 { return (myCurrent < mySize); } 73 //! Make step Next(void)74 void Next (void) 75 { myCurrent++; } 76 //! Constant value access Value(void) const77 const TheItemType& Value (void) const 78 { return myArray->myStart[myCurrent]; } 79 //! Variable value access ChangeValue(void) const80 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(). NCollection_Array2()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 NCollection_Array2(const Standard_Integer theRowLower,const Standard_Integer theRowUpper,const Standard_Integer theColLower,const Standard_Integer theColUpper)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 NCollection_Array2(const NCollection_Array2 & theOther)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 NCollection_Array2(NCollection_Array2 && theOther)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 NCollection_Array2(const TheItemType & theBegin,const Standard_Integer theRowLower,const Standard_Integer theRowUpper,const Standard_Integer theColLower,const Standard_Integer theColUpper)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 Init(const TheItemType & theValue)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) Size(void) const171 Standard_Integer Size (void) const 172 { return Length(); } 173 //! Length (number of items) Length(void) const174 Standard_Integer Length (void) const 175 { return NbRows() * NbColumns(); } 176 177 //! Returns number of rows NbRows() const178 Standard_Integer NbRows() const { return myUpperRow - myLowerRow + 1; } 179 180 //! Returns number of columns NbColumns() const181 Standard_Integer NbColumns() const { return myUpperCol - myLowerCol + 1; } 182 183 //! Returns length of the row, i.e. number of columns RowLength() const184 Standard_Integer RowLength() const { return NbColumns(); } 185 186 //! Returns length of the column, i.e. number of rows ColLength() const187 Standard_Integer ColLength() const { return NbRows(); } 188 189 //! LowerRow LowerRow(void) const190 Standard_Integer LowerRow (void) const 191 { return myLowerRow; } 192 //! UpperRow UpperRow(void) const193 Standard_Integer UpperRow (void) const 194 { return myUpperRow; } 195 //! LowerCol LowerCol(void) const196 Standard_Integer LowerCol (void) const 197 { return myLowerCol; } 198 //! UpperCol UpperCol(void) const199 Standard_Integer UpperCol (void) const 200 { return myUpperCol; } 201 202 //! myDeletable flag IsDeletable(void) const203 Standard_Boolean IsDeletable (void) const 204 { return myDeletable; } 205 206 //! Assignment Assign(const NCollection_Array2 & theOther)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. Move(NCollection_Array2 & theOther)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 operator =(const NCollection_Array2 & theOther)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() operator =(NCollection_Array2 && theOther)261 NCollection_Array2& operator= (NCollection_Array2&& theOther) 262 { 263 return Move (theOther); 264 } 265 #endif 266 267 //! Constant value access Value(const Standard_Integer theRow,const Standard_Integer theCol) const268 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 operator ()(const Standard_Integer theRow,const Standard_Integer theCol) const277 const TheItemType& operator() (const Standard_Integer theRow, 278 const Standard_Integer theCol) const 279 { return Value (theRow,theCol); } 280 281 //! Variable value access ChangeValue(const Standard_Integer theRow,const Standard_Integer theCol)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 operator ()(const Standard_Integer theRow,const Standard_Integer theCol)291 TheItemType& operator() (const Standard_Integer theRow, 292 const Standard_Integer theCol) 293 { return ChangeValue (theRow,theCol); } 294 295 //! SetValue SetValue(const Standard_Integer theRow,const Standard_Integer theCol,const TheItemType & theItem)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 Resize(Standard_Integer theRowLower,Standard_Integer theRowUpper,Standard_Integer theColLower,Standard_Integer theColUpper,Standard_Boolean theToCopyData)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 ~NCollection_Array2(void)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 Allocate(void)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. fillIndexTable(TheItemType ** theTable)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 442