0030478: Foundation Classes, NCollection_Array2 - provide Resize/Move methods consist...
authorkgv <kgv@opencascade.com>
Wed, 6 Feb 2019 09:29:21 +0000 (12:29 +0300)
committerapn <apn@opencascade.com>
Tue, 12 Feb 2019 15:54:34 +0000 (18:54 +0300)
src/NCollection/NCollection_Array2.hxx
src/QANCollection/QANCollection_Test.cxx

index c298d9e..1aa317b 100644 (file)
 * Purpose:   The class Array2 represents bi-dimensional arrays 
 *            of fixed size known at run time. 
 *            The ranges of indices are user defined.
-*            
-* Warning:   Programs clients of such class must be independant
+*
+*            Class allocates one 1D array storing full data (all Rows and Columns)
+*            and extra 1D array storing pointers to each Row.
+*
+* Warning:   Programs clients of such class must be independent
 *            of the range of the first element. Then, a C++ for
 *            loop must be written like this
 *            
@@ -85,6 +88,20 @@ public:
  public:
   // ---------- PUBLIC METHODS ------------
 
+  //! Empty constructor; should be used with caution.
+  //! @sa methods Resize() and Move().
+  NCollection_Array2()
+  : myLowerRow (1),
+    myUpperRow (0),
+    myLowerCol (1),
+    myUpperCol (0),
+    myData  (NULL),
+    myStart (NULL),
+    myDeletable(false)
+  {
+    //
+  }
+
   //! Constructor
   NCollection_Array2(const Standard_Integer theRowLower,
                      const Standard_Integer theRowUpper,
@@ -109,6 +126,23 @@ public:
     *this = theOther;
   }
 
+#ifndef OCCT_NO_RVALUE_REFERENCE
+  //! Move constructor
+  NCollection_Array2 (NCollection_Array2&& theOther)
+  : myLowerRow (theOther.myLowerRow),
+    myUpperRow (theOther.myUpperRow),
+    myLowerCol (theOther.myLowerRow),
+    myUpperCol (theOther.myUpperCol),
+    myData     (theOther.myData),
+    myStart    (theOther.myStart),
+    myDeletable(theOther.myDeletable)
+  {
+    theOther.myStart = NULL;
+    theOther.myData  = NULL;
+    theOther.myDeletable = false;
+  }
+#endif
+
   //! C array-based constructor
   NCollection_Array2(const TheItemType&     theBegin,
                      const Standard_Integer theRowLower,
@@ -138,15 +172,19 @@ public:
   { return Length(); }
   //! Length (number of items)
   Standard_Integer Length (void) const
-  { return RowLength() * ColLength(); }
+  { return NbRows() * NbColumns(); }
+
+  //! Returns number of rows
+  Standard_Integer NbRows() const { return myUpperRow - myLowerRow + 1; }
+
+  //! Returns number of columns
+  Standard_Integer NbColumns() const { return myUpperCol - myLowerCol + 1; }
 
   //! Returns length of the row, i.e. number of columns
-  Standard_Integer RowLength (void) const
-  { return (myUpperCol-myLowerCol+1); }
+  Standard_Integer RowLength() const { return NbColumns(); }
 
   //! Returns length of the column, i.e. number of rows
-  Standard_Integer ColLength (void) const
-  { return (myUpperRow-myLowerRow+1); }
+  Standard_Integer ColLength() const { return NbRows(); }
 
   //! LowerRow
   Standard_Integer LowerRow (void) const
@@ -179,12 +217,53 @@ public:
     return *this; 
   }
 
+  //! Move assignment.
+  //! This array will borrow all the data from theOther.
+  //! The moved object will be left unitialized and should not be used anymore.
+  NCollection_Array2& Move (NCollection_Array2& theOther)
+  {
+    if (&theOther == this)
+    {
+      return *this;
+    }
+
+    if (myDeletable)
+    {
+      delete[] myStart;
+    }
+    if (myData != NULL)
+    {
+      delete[] &(myData[myLowerRow]);
+    }
+
+    myLowerRow  = theOther.myLowerRow;
+    myUpperRow  = theOther.myUpperRow;
+    myLowerCol  = theOther.myLowerRow;
+    myUpperCol  = theOther.myUpperCol;
+    myData      = theOther.myData;
+    myStart     = theOther.myStart;
+    myDeletable = theOther.myDeletable;
+
+    theOther.myStart = NULL;
+    theOther.myData  = NULL;
+    theOther.myDeletable = Standard_False;
+    return *this;
+  }
+
   //! Assignment operator
   NCollection_Array2& operator= (const NCollection_Array2& theOther)
   { 
     return Assign (theOther);
   }
 
+#ifndef OCCT_NO_RVALUE_REFERENCE
+  //! Move assignment operator; @sa Move()
+  NCollection_Array2& operator= (NCollection_Array2&& theOther)
+  {
+    return Move (theOther);
+  }
+#endif
+
   //! Constant value access
   const TheItemType& Value (const Standard_Integer theRow,
                             const Standard_Integer theCol) const
@@ -222,12 +301,86 @@ public:
                                   theCol < myLowerCol || theCol > myUpperCol, "NCollection_Array2::SetValue");
     myData[theRow][theCol] = theItem;
   }
-  
+
+  //! Resizes the array to specified bounds.
+  //! No re-allocation will be done if length of array does not change,
+  //! but existing values will not be discarded if theToCopyData set to FALSE.
+  //! @param theRowLower new lower Row of array
+  //! @param theRowUpper new upper Row of array
+  //! @param theColLower new lower Column of array
+  //! @param theColUpper new upper Column of array
+  //! @param theToCopyData flag to copy existing data into new array
+  void Resize (Standard_Integer theRowLower,
+               Standard_Integer theRowUpper,
+               Standard_Integer theColLower,
+               Standard_Integer theColUpper,
+               Standard_Boolean theToCopyData)
+  {
+    Standard_RangeError_Raise_if (theRowUpper < theRowLower
+                               || theColUpper < theColLower, "NCollection_Array2::Resize");
+    const Standard_Integer anOldNbRows  = NbRows();
+    const Standard_Integer anOldNbCols  = NbColumns();
+    const Standard_Integer aLowerRowOld = myLowerRow;
+    const Standard_Integer aLowerColOld = myLowerCol;
+    const Standard_Integer aNewNbRows   = theRowUpper - theRowLower + 1;
+    const Standard_Integer aNewNbCols   = theColUpper - theColLower + 1;
+
+    TheItemType*  aStartOld = myStart;
+    TheItemType** aTableOld = myData != NULL ? myData + aLowerRowOld : NULL;
+    myLowerRow = theRowLower;
+    myUpperRow = theRowUpper;
+    myLowerCol = theColLower;
+    myUpperCol = theColUpper;
+    if (aNewNbRows == anOldNbRows
+     && aNewNbCols == anOldNbCols)
+    {
+      if (myLowerCol != aLowerColOld)
+      {
+        fillIndexTable (aTableOld);
+      }
+      myData = aTableOld - myLowerRow;
+      return;
+    }
+
+    if (myDeletable
+    && !theToCopyData)
+    {
+      delete[] aStartOld;
+    }
+    delete[] aTableOld;
+
+    Allocate();
+    if (!theToCopyData)
+    {
+      myDeletable = Standard_True;
+      return;
+    }
+
+    const Standard_Integer aNbRowsToCopy = Min (anOldNbRows, aNewNbRows);
+    const Standard_Integer aNbColsToCopy = Min (anOldNbCols, aNewNbCols);
+    for (Standard_Integer aRowIter = 0; aRowIter < aNbRowsToCopy; ++aRowIter)
+    {
+      for (Standard_Integer aColIter = 0; aColIter < aNbColsToCopy; ++aColIter)
+      {
+        myStart[size_t(aRowIter) * size_t(aNewNbCols) + size_t(aColIter)] = aStartOld[size_t(aRowIter) * size_t(anOldNbCols) + size_t(aColIter)];
+      }
+    }
+
+    if (myDeletable)
+    {
+      delete[] aStartOld;
+    }
+    myDeletable = Standard_True;
+  }
+
   //! Destructor - releases the memory
   ~NCollection_Array2 (void)
   { 
     if (myDeletable) delete [] myStart;
-    delete [] &(myData[myLowerRow]);
+    if (myData != NULL)
+    {
+      delete[] &(myData[myLowerRow]);
+    }
   }
 
  private:
@@ -236,28 +389,37 @@ public:
   //! Allocate memory for the array, set up indirection table
   void Allocate (void)
   {
-    const Standard_Integer iRowSize = myUpperCol - myLowerCol + 1;
-    const Standard_Integer iColSize = myUpperRow - myLowerRow + 1;
-    Standard_RangeError_Raise_if (iRowSize <= 0  || iColSize <= 0, "NCollection_Array2::Allocate");
-    if (myDeletable) {
+    const Standard_Integer aNbRows = NbRows();
+    const Standard_Integer aNbCols = NbColumns();
+    Standard_RangeError_Raise_if (aNbRows <= 0  || aNbCols <= 0, "NCollection_Array2::Allocate");
+    if (myDeletable)
+    {
       // allocation of the data in the array
-      myStart = new TheItemType[iRowSize * iColSize];
+      myStart = new TheItemType[size_t(aNbRows) * size_t(aNbCols)];
       Standard_OutOfMemory_Raise_if (!myStart, "NCollection_Array2 : Allocation failed");
     }
     // else myStart is set to the beginning of the given array
-    TheItemType** pTable = new TheItemType* [iColSize];
+
+    TheItemType** pTable = new TheItemType* [aNbRows];
     Standard_OutOfMemory_Raise_if (!pTable, "NCollection_Array2 : Allocation failed");
+    fillIndexTable (pTable);
+  }
 
-    // Items of pTable point to the '0'th items in the rows of the array
-    TheItemType* pRow = myStart - myLowerCol;
-    for (Standard_Integer i = 0; i < iColSize; i++) 
+  //! Fill index table for accessing array elements.
+  void fillIndexTable (TheItemType** theTable)
+  {
+    // Items of table point to the 0th items in the rows of the array
+    TheItemType* aRow = myStart - myLowerCol;
+    const Standard_Integer aNbRows = NbRows();
+    const Standard_Size    aNbCols = NbColumns();
+    for (Standard_Integer aRowIter = 0; aRowIter < aNbRows; ++aRowIter)
     {
-      pTable[i] = pRow;
-      pRow += iRowSize;
+      theTable[aRowIter] = aRow;
+      aRow += aNbCols;
     }
 
-    // Set myData to the '0'th row pointer of the pTable
-    myData = pTable - myLowerRow;
+    // Set myData to the 0th row pointer of the table
+    myData = theTable - myLowerRow;
   }
 
  protected:
index 658aad8..154c7c2 100644 (file)
@@ -716,6 +716,42 @@ static Standard_Integer QANColTestArray2(Draw_Interpretor& di, Standard_Integer
   }
   QANCollection_Array2Func anArr2(LowerRow, UpperRow, LowerCol, UpperCol);
   TestArray2(anArr2);
+
+  // check resize
+  for (int aPass = 0; aPass <= 5; ++aPass)
+  {
+    Standard_Integer aNewLowerRow = LowerRow, aNewUpperRow = UpperRow, aNewLowerCol = LowerCol, aNewUpperCol = UpperCol;
+    switch (aPass)
+    {
+      case 0: aNewLowerRow -= 1; break;
+      case 1: aNewLowerCol -= 1; break;
+      case 2: aNewLowerRow -= 1; aNewLowerCol -= 1; break;
+      case 3: aNewUpperRow += 1; break;
+      case 4: aNewUpperCol += 1; break;
+      case 5: aNewUpperRow += 1; aNewUpperCol += 1; break;
+    }
+    QANCollection_Array2Func anArr2Copy = anArr2;
+    anArr2Copy.Resize (aNewLowerRow, aNewUpperRow, aNewLowerCol, aNewUpperCol, true);
+    const Standard_Integer aNbRowsMin = Min (anArr2.NbRows(),    anArr2Copy.NbRows());
+    const Standard_Integer aNbColsMin = Min (anArr2.NbColumns(), anArr2Copy.NbColumns());
+    for (Standard_Integer aRowIter = 0; aRowIter < aNbRowsMin; ++aRowIter)
+    {
+      for (Standard_Integer aColIter = 0; aColIter < aNbColsMin; ++aColIter)
+      {
+        const gp_Pnt& aPnt1 = anArr2    .Value (aRowIter +     anArr2.LowerRow(), aColIter +     anArr2.LowerCol());
+        const gp_Pnt& aPnt2 = anArr2Copy.Value (aRowIter + anArr2Copy.LowerRow(), aColIter + anArr2Copy.LowerCol());
+        if (!aPnt1.IsEqual (aPnt2, gp::Resolution()))
+        {
+          std::cerr << "Error: 2D array is not properly resized\n";
+          return 1;
+        }
+      }
+    }
+  }
+
+  QANCollection_Array2Func anArr2Copy2 = anArr2;
+  anArr2Copy2.Resize (LowerRow - 1, UpperRow - 1, LowerCol + 1, UpperCol + 1, false);
+
   return 0;
 }