]> OCCT Git - occt.git/commitdiff
Foundation Classes, math_DoubleTab - Rework to NCollection container (#607)
authorPasukhin Dmitry <dpasukhi@opencascade.com>
Sun, 13 Jul 2025 09:58:44 +0000 (10:58 +0100)
committerGitHub <noreply@github.com>
Sun, 13 Jul 2025 09:58:44 +0000 (10:58 +0100)
- Refactors `math_DoubleTab` to use `NCollection_Array2` as its underlying container
- Eemoves the old C‐array implementation, and updates collection classes to improve move semantics and bounds manipulation.
- Rework `math_DoubleTab` to wrap `NCollection_Array2`, with buffer optimization for small sizes
- Enhance `NCollection_Array2` and `NCollection_Array1` with proper move semantics and bound‐updating methods
- Remove legacy `.lxx`/`.cxx` implementations, add tests and update CMake file lists

13 files changed:
src/FoundationClasses/TKMath/GTests/FILES.cmake
src/FoundationClasses/TKMath/GTests/math_DoubleTab_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKMath/math/FILES.cmake
src/FoundationClasses/TKMath/math/math_DoubleTab.cxx [deleted file]
src/FoundationClasses/TKMath/math/math_DoubleTab.hxx
src/FoundationClasses/TKMath/math/math_DoubleTab.lxx [deleted file]
src/FoundationClasses/TKMath/math/math_Matrix.hxx
src/FoundationClasses/TKMath/math/math_Matrix.lxx
src/FoundationClasses/TKernel/GTests/FILES.cmake
src/FoundationClasses/TKernel/GTests/NCollection_Array1_Test.cxx
src/FoundationClasses/TKernel/GTests/NCollection_Array2_Test.cxx [new file with mode: 0644]
src/FoundationClasses/TKernel/NCollection/NCollection_Array1.hxx
src/FoundationClasses/TKernel/NCollection/NCollection_Array2.hxx

index 1c049c271a23695e5d80540742211cd3a01cdaa1..ab7d9a4b083826872273582b51bd744d25b9b10e 100644 (file)
@@ -4,5 +4,6 @@ set(OCCT_TKMath_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
 set(OCCT_TKMath_GTests_FILES
   Bnd_BoundSortBox_Test.cxx
   ElCLib_Test.cxx
+  math_DoubleTab_Test.cxx
   math_Matrix_Test.cxx
 )
diff --git a/src/FoundationClasses/TKMath/GTests/math_DoubleTab_Test.cxx b/src/FoundationClasses/TKMath/GTests/math_DoubleTab_Test.cxx
new file mode 100644 (file)
index 0000000..8f5f294
--- /dev/null
@@ -0,0 +1,215 @@
+// Copyright (c) 2025 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <math_DoubleTab.hxx>
+
+#include <gtest/gtest.h>
+
+#include <Standard_Real.hxx>
+#include <Standard_Integer.hxx>
+#include <Precision.hxx>
+
+// Tests for constructors
+TEST(MathDoubleTabTest, DefaultConstructor)
+{
+  // Test standard constructor with ranges
+  math_DoubleTab aTab(1, 3, 1, 3);
+
+  // Initialize with test values
+  aTab.Init(5.0);
+
+  // Check all values are set to 5.0
+  for (Standard_Integer anI = 1; anI <= 3; anI++)
+  {
+    for (Standard_Integer aJ = 1; aJ <= 3; aJ++)
+    {
+      EXPECT_DOUBLE_EQ(aTab.Value(anI, aJ), 5.0);
+      EXPECT_DOUBLE_EQ(aTab(anI, aJ), 5.0); // Test operator()
+    }
+  }
+}
+
+TEST(MathDoubleTabTest, ExternalArrayConstructor)
+{
+  // Create external array
+  Standard_Real anArray[9] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
+
+  // Create math_DoubleTab from external array
+  math_DoubleTab aTab(anArray, 1, 3, 1, 3);
+
+  // Check values are correctly accessed
+  Standard_Integer anIndex = 0;
+  for (Standard_Integer anI = 1; anI <= 3; anI++)
+  {
+    for (Standard_Integer aJ = 1; aJ <= 3; aJ++)
+    {
+      EXPECT_DOUBLE_EQ(aTab.Value(anI, aJ), anArray[anIndex]);
+      anIndex++;
+    }
+  }
+}
+
+TEST(MathDoubleTabTest, CopyConstructor)
+{
+  // Create original array
+  math_DoubleTab aOriginal(1, 3, 1, 3);
+  aOriginal.Init(10.0);
+
+  // Set some specific values
+  aOriginal.Value(1, 1) = 1.5;
+  aOriginal.Value(2, 2) = 2.5;
+  aOriginal.Value(3, 3) = 3.5;
+
+  // Create copy
+  math_DoubleTab aCopy(aOriginal);
+
+  // Check values are copied correctly
+  EXPECT_DOUBLE_EQ(aCopy.Value(1, 1), 1.5);
+  EXPECT_DOUBLE_EQ(aCopy.Value(2, 2), 2.5);
+  EXPECT_DOUBLE_EQ(aCopy.Value(3, 3), 3.5);
+  EXPECT_DOUBLE_EQ(aCopy.Value(1, 2), 10.0); // Check other values too
+}
+
+// Tests for basic operations
+TEST(MathDoubleTabTest, InitOperation)
+{
+  math_DoubleTab aTab(0, 2, 0, 2);
+
+  // Initialize with specific value
+  aTab.Init(7.5);
+
+  // Check all elements are set
+  for (Standard_Integer anI = 0; anI <= 2; anI++)
+  {
+    for (Standard_Integer aJ = 0; aJ <= 2; aJ++)
+    {
+      EXPECT_DOUBLE_EQ(aTab.Value(anI, aJ), 7.5);
+    }
+  }
+}
+
+TEST(MathDoubleTabTest, ValueAccess)
+{
+  math_DoubleTab aTab(1, 2, 1, 2);
+
+  // Set values using Value method
+  aTab.Value(1, 1) = 11.0;
+  aTab.Value(1, 2) = 12.0;
+  aTab.Value(2, 1) = 21.0;
+  aTab.Value(2, 2) = 22.0;
+
+  // Check values using operator()
+  EXPECT_DOUBLE_EQ(aTab(1, 1), 11.0);
+  EXPECT_DOUBLE_EQ(aTab(1, 2), 12.0);
+  EXPECT_DOUBLE_EQ(aTab(2, 1), 21.0);
+  EXPECT_DOUBLE_EQ(aTab(2, 2), 22.0);
+}
+
+TEST(MathDoubleTabTest, OperatorAccess)
+{
+  math_DoubleTab aTab(-1, 1, -1, 1);
+
+  // Set values using operator()
+  aTab(-1, -1) = -11.0;
+  aTab(-1, 0)  = -10.0;
+  aTab(-1, 1)  = -9.0;
+  aTab(0, -1)  = -1.0;
+  aTab(0, 0)   = 0.0;
+  aTab(0, 1)   = 1.0;
+  aTab(1, -1)  = 9.0;
+  aTab(1, 0)   = 10.0;
+  aTab(1, 1)   = 11.0;
+
+  // Check values using Value method
+  EXPECT_DOUBLE_EQ(aTab.Value(-1, -1), -11.0);
+  EXPECT_DOUBLE_EQ(aTab.Value(-1, 0), -10.0);
+  EXPECT_DOUBLE_EQ(aTab.Value(-1, 1), -9.0);
+  EXPECT_DOUBLE_EQ(aTab.Value(0, -1), -1.0);
+  EXPECT_DOUBLE_EQ(aTab.Value(0, 0), 0.0);
+  EXPECT_DOUBLE_EQ(aTab.Value(0, 1), 1.0);
+  EXPECT_DOUBLE_EQ(aTab.Value(1, -1), 9.0);
+  EXPECT_DOUBLE_EQ(aTab.Value(1, 0), 10.0);
+  EXPECT_DOUBLE_EQ(aTab.Value(1, 1), 11.0);
+}
+
+TEST(MathDoubleTabTest, CopyMethod)
+{
+  // Create source array
+  math_DoubleTab aSource(1, 2, 1, 2);
+  aSource.Value(1, 1) = 100.0;
+  aSource.Value(1, 2) = 200.0;
+  aSource.Value(2, 1) = 300.0;
+  aSource.Value(2, 2) = 400.0;
+
+  // Create destination array
+  math_DoubleTab aDest(1, 2, 1, 2);
+  aDest.Init(0.0);
+
+  // Copy from source to destination
+  aSource.Copy(aDest);
+
+  // Check values are copied
+  EXPECT_DOUBLE_EQ(aDest.Value(1, 1), 100.0);
+  EXPECT_DOUBLE_EQ(aDest.Value(1, 2), 200.0);
+  EXPECT_DOUBLE_EQ(aDest.Value(2, 1), 300.0);
+  EXPECT_DOUBLE_EQ(aDest.Value(2, 2), 400.0);
+}
+
+// Tests for buffer optimization
+TEST(MathDoubleTabTest, SmallArrayOptimization)
+{
+  // Test that small arrays (<=16 elements) use buffer optimization
+  // 4x4 = 16 elements, should use buffer
+  math_DoubleTab aSmallTab(1, 4, 1, 4);
+  aSmallTab.Init(42.0);
+
+  // Set and read values to ensure it works correctly
+  aSmallTab.Value(2, 3) = 123.45;
+  EXPECT_DOUBLE_EQ(aSmallTab.Value(2, 3), 123.45);
+  EXPECT_DOUBLE_EQ(aSmallTab.Value(1, 1), 42.0);
+}
+
+TEST(MathDoubleTabTest, LargeArrayAllocation)
+{
+  // Test that large arrays (>16 elements) allocate memory
+  // 5x5 = 25 elements, should allocate
+  math_DoubleTab aLargeTab(1, 5, 1, 5);
+  aLargeTab.Init(99.99);
+
+  // Set and read values to ensure it works correctly
+  aLargeTab.Value(3, 4) = 987.65;
+  EXPECT_DOUBLE_EQ(aLargeTab.Value(3, 4), 987.65);
+  EXPECT_DOUBLE_EQ(aLargeTab.Value(1, 1), 99.99);
+}
+
+// Tests for edge cases
+TEST(MathDoubleTabTest, SingleElement)
+{
+  // Test with single element array
+  math_DoubleTab aSingle(5, 5, 10, 10);
+  aSingle.Value(5, 10) = 777.0;
+
+  EXPECT_DOUBLE_EQ(aSingle.Value(5, 10), 777.0);
+  EXPECT_DOUBLE_EQ(aSingle(5, 10), 777.0);
+}
+
+TEST(MathDoubleTabTest, NegativeIndices)
+{
+  // Test with negative indices
+  math_DoubleTab aNegTab(-5, -1, -3, -1);
+  aNegTab.Init(-1.0);
+
+  aNegTab.Value(-3, -2) = -999.0;
+  EXPECT_DOUBLE_EQ(aNegTab.Value(-3, -2), -999.0);
+  EXPECT_DOUBLE_EQ(aNegTab.Value(-5, -3), -1.0);
+}
index 31f30cffdec6b3e9983113351a52119f3f70a315..a5865e1f4a4ae956cba6a55f406371402cbcbb81 100644 (file)
@@ -31,9 +31,7 @@ set(OCCT_math_FILES
   math_DirectPolynomialRoots.cxx
   math_DirectPolynomialRoots.hxx
   math_DirectPolynomialRoots.lxx
-  math_DoubleTab.cxx
   math_DoubleTab.hxx
-  math_DoubleTab.lxx
   math_EigenValuesSearcher.cxx
   math_EigenValuesSearcher.hxx
   math_FRPR.cxx
diff --git a/src/FoundationClasses/TKMath/math/math_DoubleTab.cxx b/src/FoundationClasses/TKMath/math/math_DoubleTab.cxx
deleted file mode 100644 (file)
index ffe45a0..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 1997-1999 Matra Datavision
-// Copyright (c) 1999-2014 OPEN CASCADE SAS
-//
-// This file is part of Open CASCADE Technology software library.
-//
-// This library is free software; you can redistribute it and/or modify it under
-// the terms of the GNU Lesser General Public License version 2.1 as published
-// by the Free Software Foundation, with special exception defined in the file
-// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
-// distribution for complete text of the license and disclaimer of any warranty.
-//
-// Alternatively, this file may be used under the terms of Open CASCADE
-// commercial license or contractual agreement.
-
-// Lpa, le 7/02/92
-
-#include <math_DoubleTab.hxx>
-#include <Standard_OutOfRange.hxx>
-
-// macro to get size of C array
-#define CARRAY_LENGTH(arr) (int)(sizeof(arr) / sizeof(arr[0]))
-
-void math_DoubleTab::Allocate()
-{
-  Standard_Integer RowNumber = UppR - LowR + 1;
-  Standard_Integer ColNumber = UppC - LowC + 1;
-
-  if (isAllocated)
-    Addr = (Standard_Real*)Standard::Allocate(RowNumber * ColNumber * sizeof(Standard_Real));
-}
-
-math_DoubleTab::math_DoubleTab(const Standard_Integer LowerRow,
-                               const Standard_Integer UpperRow,
-                               const Standard_Integer LowerCol,
-                               const Standard_Integer UpperCol)
-    : Addr(Buf),
-      isAllocated((UpperRow - LowerRow + 1) * (UpperCol - LowerCol + 1) > CARRAY_LENGTH(Buf)),
-      LowR(LowerRow),
-      UppR(UpperRow),
-      LowC(LowerCol),
-      UppC(UpperCol)
-{
-  Allocate();
-}
-
-math_DoubleTab::math_DoubleTab(const Standard_Address Tab,
-                               const Standard_Integer LowerRow,
-                               const Standard_Integer UpperRow,
-                               const Standard_Integer LowerCol,
-                               const Standard_Integer UpperCol)
-    : Addr(Tab),
-      isAllocated(Standard_False),
-      LowR(LowerRow),
-      UppR(UpperRow),
-      LowC(LowerCol),
-      UppC(UpperCol)
-{
-  Allocate();
-}
-
-void math_DoubleTab::Init(const Standard_Real InitValue)
-{
-  for (Standard_Integer anIndex = 0; anIndex < (UppR - LowR + 1) * (UppC - LowC + 1); anIndex++)
-  {
-    ((Standard_Real*)Addr)[anIndex] = InitValue;
-  }
-}
-
-math_DoubleTab::math_DoubleTab(const math_DoubleTab& Other)
-    : Addr(Buf),
-      isAllocated((Other.UppR - Other.LowR + 1) * (Other.UppC - Other.LowC + 1)
-                  > CARRAY_LENGTH(Buf)),
-      LowR(Other.LowR),
-      UppR(Other.UppR),
-      LowC(Other.LowC),
-      UppC(Other.UppC)
-{
-  Allocate();
-  memmove(Addr, Other.Addr, (int)((UppR - LowR + 1) * (UppC - LowC + 1) * sizeof(Standard_Real)));
-}
-
-void math_DoubleTab::Free()
-{
-  // free the data
-  if (isAllocated)
-  {
-    Standard::Free(Addr);
-  }
-
-  Addr = 0;
-}
-
-void math_DoubleTab::SetLowerRow(const Standard_Integer LowerRow)
-{
-  UppR = UppR - LowR + LowerRow;
-  LowR = LowerRow;
-}
-
-void math_DoubleTab::SetLowerCol(const Standard_Integer LowerCol)
-{
-  UppC = UppC - LowC + LowerCol;
-  LowC = LowerCol;
-}
index 2c6fc3b37e1adbc5c3a5ed78eb13b50219f0ae39..be337d45dee5914e205a10437797ba7406fc102c 100644 (file)
 #include <Standard.hxx>
 #include <Standard_DefineAlloc.hxx>
 #include <Standard_Handle.hxx>
+#include <NCollection_Array2.hxx>
 
 #include <Standard_Real.hxx>
 #include <Standard_Boolean.hxx>
 
+#include <array>
+
 class math_DoubleTab
 {
+  static const Standard_Integer THE_BUFFER_SIZE = 16;
+
 public:
-  DEFINE_STANDARD_ALLOC
+  DEFINE_STANDARD_ALLOC;
+  DEFINE_NCOLLECTION_ALLOC;
 
-  Standard_EXPORT math_DoubleTab(const Standard_Integer LowerRow,
-                                 const Standard_Integer UpperRow,
-                                 const Standard_Integer LowerCol,
-                                 const Standard_Integer UpperCol);
+public:
+  //! Constructor for ranges [theLowerRow..theUpperRow, theLowerCol..theUpperCol]
+  math_DoubleTab(const Standard_Integer theLowerRow,
+                 const Standard_Integer theUpperRow,
+                 const Standard_Integer theLowerCol,
+                 const Standard_Integer theUpperCol)
+      : myBuffer{},
+        myArray(
+          (theUpperRow - theLowerRow + 1) * (theUpperCol - theLowerCol + 1) <= THE_BUFFER_SIZE
+            ? NCollection_Array2<Standard_Real>(*myBuffer.data(),
+                                                theLowerRow,
+                                                theUpperRow,
+                                                theLowerCol,
+                                                theUpperCol)
+            : NCollection_Array2<Standard_Real>(theLowerRow, theUpperRow, theLowerCol, theUpperCol))
+  {
+  }
+
+public:
+  //! Constructor from external data array
+  math_DoubleTab(const Standard_Address theTab,
+                 const Standard_Integer theLowerRow,
+                 const Standard_Integer theUpperRow,
+                 const Standard_Integer theLowerCol,
+                 const Standard_Integer theUpperCol)
+      : myArray(*static_cast<const Standard_Real*>(theTab),
+                theLowerRow,
+                theUpperRow,
+                theLowerCol,
+                theUpperCol)
+  {
+  }
 
-  Standard_EXPORT math_DoubleTab(const Standard_Address Tab,
-                                 const Standard_Integer LowerRow,
-                                 const Standard_Integer UpperRow,
-                                 const Standard_Integer LowerCol,
-                                 const Standard_Integer UpperCol);
+  //! Initialize all elements with theInitValue
+  void Init(const Standard_Real theInitValue) { myArray.Init(theInitValue); }
 
-  Standard_EXPORT void Init(const Standard_Real InitValue);
+  //! Copy constructor
+  math_DoubleTab(const math_DoubleTab& theOther)
+      : myArray(theOther.myArray)
+  {
+  }
 
-  Standard_EXPORT math_DoubleTab(const math_DoubleTab& Other);
+  //! Copy data to theOther
+  void Copy(math_DoubleTab& theOther) const { theOther.myArray.Assign(myArray); }
 
-  void Copy(math_DoubleTab& Other) const;
+  //! Set lower row index
+  void SetLowerRow(const Standard_Integer theLowerRow) { myArray.UpdateLowerRow(theLowerRow); }
 
-  Standard_EXPORT void SetLowerRow(const Standard_Integer LowerRow);
+  //! Set lower column index
+  void SetLowerCol(const Standard_Integer theLowerCol) { myArray.UpdateLowerCol(theLowerCol); }
 
-  Standard_EXPORT void SetLowerCol(const Standard_Integer LowerCol);
+  //! Access element at (theRowIndex, theColIndex)
+  const Standard_Real& Value(const Standard_Integer theRowIndex,
+                             const Standard_Integer theColIndex) const
+  {
+    return myArray.Value(theRowIndex, theColIndex);
+  }
 
-  Standard_Real& Value(const Standard_Integer RowIndex, const Standard_Integer ColIndex) const;
+  //! Change element at (theRowIndex, theColIndex)
+  Standard_Real& Value(const Standard_Integer theRowIndex, const Standard_Integer theColIndex)
+  {
+    return myArray.ChangeValue(theRowIndex, theColIndex);
+  }
 
-  Standard_Real& operator()(const Standard_Integer RowIndex, const Standard_Integer ColIndex) const
+  //! Operator() - alias to Value
+  const Standard_Real& operator()(const Standard_Integer theRowIndex,
+                                  const Standard_Integer theColIndex) const
   {
-    return Value(RowIndex, ColIndex);
+    return Value(theRowIndex, theColIndex);
   }
 
-  Standard_EXPORT void Free();
+  //! Operator() - alias to ChangeValue
+  Standard_Real& operator()(const Standard_Integer theRowIndex, const Standard_Integer theColIndex)
+  {
+    return Value(theRowIndex, theColIndex);
+  }
 
-  ~math_DoubleTab() { Free(); }
+  //! Destructor
+  ~math_DoubleTab() = default;
 
-protected:
 private:
-  Standard_EXPORT void Allocate();
-
-  Standard_Address Addr;
-  Standard_Real    Buf[16]{};
-  Standard_Boolean isAllocated;
-  Standard_Integer LowR;
-  Standard_Integer UppR;
-  Standard_Integer LowC;
-  Standard_Integer UppC;
+  std::array<Standard_Real, THE_BUFFER_SIZE> myBuffer;
+  NCollection_Array2<Standard_Real>          myArray;
 };
 
-#include <math_DoubleTab.lxx>
-
 #endif // _math_DoubleTab_HeaderFile
diff --git a/src/FoundationClasses/TKMath/math/math_DoubleTab.lxx b/src/FoundationClasses/TKMath/math/math_DoubleTab.lxx
deleted file mode 100644 (file)
index 294efd0..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 1997-1999 Matra Datavision
-// Copyright (c) 1999-2014 OPEN CASCADE SAS
-//
-// This file is part of Open CASCADE Technology software library.
-//
-// This library is free software; you can redistribute it and/or modify it under
-// the terms of the GNU Lesser General Public License version 2.1 as published
-// by the Free Software Foundation, with special exception defined in the file
-// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
-// distribution for complete text of the license and disclaimer of any warranty.
-//
-// Alternatively, this file may be used under the terms of Open CASCADE
-// commercial license or contractual agreement.
-
-// Lpa, le 7/02/92
-
-#include <string.h>
-
-#include <Standard_OutOfRange.hxx>
-
-inline Standard_Real& math_DoubleTab::Value(const Standard_Integer RowIndex,
-                                            const Standard_Integer ColIndex) const
-{
-  return ((Standard_Real*)Addr)[(UppC - LowC + 1) * (RowIndex - LowR) + (ColIndex - LowC)];
-}
-
-inline void math_DoubleTab::Copy(math_DoubleTab& Other) const
-{
-  memmove(Other.Addr, Addr, (int)((UppR - LowR + 1) * (UppC - LowC + 1) * sizeof(Standard_Real)));
-}
index e05b4e917e6e361b57907a2d15153dfc147bf17e..bacdfd38b4d8af405f4d6d60319f0aa33119466d 100644 (file)
@@ -349,13 +349,24 @@ public:
   //! An exception is raised if the dimensions are different.
   Standard_EXPORT void Subtract(const math_Matrix& Left, const math_Matrix& Right);
 
+  //! Accesses the value of index <Row>
+  //! and <Col> of a matrix.
+  //! An exception is raised if <Row> and <Col> are not
+  //! in the correct range.
+  const Standard_Real& Value(const Standard_Integer Row, const Standard_Integer Col) const;
+
   //! Accesses (in read or write mode) the value of index <Row>
   //! and <Col> of a matrix.
   //! An exception is raised if <Row> and <Col> are not
   //! in the correct range.
-  Standard_Real& Value(const Standard_Integer Row, const Standard_Integer Col) const;
+  Standard_Real& Value(const Standard_Integer Row, const Standard_Integer Col);
+
+  const Standard_Real& operator()(const Standard_Integer Row, const Standard_Integer Col) const
+  {
+    return Value(Row, Col);
+  }
 
-  Standard_Real& operator()(const Standard_Integer Row, const Standard_Integer Col) const
+  Standard_Real& operator()(const Standard_Integer Row, const Standard_Integer Col)
   {
     return Value(Row, Col);
   }
index 07cbca89f12fe6fb0be9a4fa0318bcfe0629164e..aa11c220a02d0b3314999c0abcb8491c07db0921 100644 (file)
@@ -27,14 +27,23 @@ inline math_Matrix operator*(const Standard_Real Left, const math_Matrix& Right)
   return Right.Multiplied(Left);
 }
 
-inline Standard_Real& math_Matrix::Value(const Standard_Integer Row,
-                                         const Standard_Integer Col) const
+inline const Standard_Real& math_Matrix::Value(const Standard_Integer Row,
+                                               const Standard_Integer Col) const
 {
   Standard_RangeError_Raise_if(((Row < LowerRowIndex) || (Row > UpperRowIndex)
                                 || (Col < LowerColIndex) || (Col > UpperColIndex)),
                                " ");
 
-  return Array(Row, Col);
+  return Array.Value(Row, Col);
+}
+
+inline Standard_Real& math_Matrix::Value(const Standard_Integer Row, const Standard_Integer Col)
+{
+  Standard_RangeError_Raise_if(((Row < LowerRowIndex) || (Row > UpperRowIndex)
+                                || (Col < LowerColIndex) || (Col > UpperColIndex)),
+                               " ");
+
+  return Array.Value(Row, Col);
 }
 
 inline Standard_Integer math_Matrix::RowNumber() const
index e11faf7f6f9e37ce751c530cfcf38213681420e6..84d82d1f066c286302f5807b0165864219a60084 100644 (file)
@@ -3,6 +3,7 @@ set(OCCT_TKernel_GTests_FILES_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
 
 set(OCCT_TKernel_GTests_FILES
   NCollection_Array1_Test.cxx
+  NCollection_Array2_Test.cxx
   NCollection_BaseAllocator_Test.cxx
   NCollection_DataMap_Test.cxx
   NCollection_DoubleMap_Test.cxx
index 01e9a74b3536f4fac70cc47a481f1593fd6ed312..9995c3e652bc66e4fad4e996e1ccb613e9e687d6 100644 (file)
 
 #include <gtest/gtest.h>
 
-// Test fixture for NCollection_Array1 tests
-class NCollection_Array1Test : public testing::Test
-{
-protected:
-  void SetUp() override {}
-
-  void TearDown() override {}
-};
-
-TEST_F(NCollection_Array1Test, DefaultConstructor)
+TEST(NCollection_Array1Test, DefaultConstructor)
 {
   // Default constructor should not compile as it's explicitly deleted
   // NCollection_Array1<Standard_Integer> anArray;
@@ -37,7 +28,7 @@ TEST_F(NCollection_Array1Test, DefaultConstructor)
   EXPECT_EQ(10, anArray.Upper());
 }
 
-TEST_F(NCollection_Array1Test, ConstructorWithBounds)
+TEST(NCollection_Array1Test, ConstructorWithBounds)
 {
   // Test constructor with explicit bounds
   NCollection_Array1<Standard_Integer> anArray(1, 5);
@@ -46,7 +37,7 @@ TEST_F(NCollection_Array1Test, ConstructorWithBounds)
   EXPECT_EQ(5, anArray.Upper());
 }
 
-TEST_F(NCollection_Array1Test, ConstructorWithNegativeBounds)
+TEST(NCollection_Array1Test, ConstructorWithNegativeBounds)
 {
   // Test constructor with negative bounds
   NCollection_Array1<Standard_Integer> anArray(-3, 2);
@@ -55,7 +46,7 @@ TEST_F(NCollection_Array1Test, ConstructorWithNegativeBounds)
   EXPECT_EQ(2, anArray.Upper());
 }
 
-TEST_F(NCollection_Array1Test, AssignmentValue)
+TEST(NCollection_Array1Test, AssignmentValue)
 {
   NCollection_Array1<Standard_Integer> anArray(1, 5);
 
@@ -78,7 +69,7 @@ TEST_F(NCollection_Array1Test, AssignmentValue)
   }
 }
 
-TEST_F(NCollection_Array1Test, CopyConstructor)
+TEST(NCollection_Array1Test, CopyConstructor)
 {
   NCollection_Array1<Standard_Integer> anArray1(1, 5);
 
@@ -106,7 +97,7 @@ TEST_F(NCollection_Array1Test, CopyConstructor)
   EXPECT_NE(anArray1(3), anArray2(3));
 }
 
-TEST_F(NCollection_Array1Test, ValueAccess)
+TEST(NCollection_Array1Test, ValueAccess)
 {
   NCollection_Array1<Standard_Integer> anArray(1, 5);
 
@@ -124,7 +115,7 @@ TEST_F(NCollection_Array1Test, ValueAccess)
   }
 }
 
-TEST_F(NCollection_Array1Test, ChangeValueAccess)
+TEST(NCollection_Array1Test, ChangeValueAccess)
 {
   NCollection_Array1<Standard_Integer> anArray(1, 5);
 
@@ -153,7 +144,7 @@ TEST_F(NCollection_Array1Test, ChangeValueAccess)
   }
 }
 
-TEST_F(NCollection_Array1Test, AssignmentOperator)
+TEST(NCollection_Array1Test, AssignmentOperator)
 {
   NCollection_Array1<Standard_Integer> anArray1(1, 5);
 
@@ -179,7 +170,7 @@ TEST_F(NCollection_Array1Test, AssignmentOperator)
   }
 }
 
-TEST_F(NCollection_Array1Test, Move)
+TEST(NCollection_Array1Test, Move)
 {
   NCollection_Array1<Standard_Integer> anArray1(1, 5);
 
@@ -199,15 +190,12 @@ TEST_F(NCollection_Array1Test, Move)
   EXPECT_EQ(1, anArray2.Lower());
   EXPECT_EQ(5, anArray2.Upper());
 
-  // Original array is keep referecing the same data
-  EXPECT_EQ(anArray1.Lower(), anArray2.Lower());
-  EXPECT_EQ(anArray1.Upper(), anArray2.Upper());
-  EXPECT_EQ(anArray1(1), anArray2(1));
-  EXPECT_EQ(anArray1(2), anArray2(2));
-  EXPECT_EQ(5, anArray1.Length());
+  // Original array is not keep referecing the same data
+  EXPECT_EQ(anArray1.Length(), 0);
+  EXPECT_EQ(anArray1.Lower(), 1);
 }
 
-TEST_F(NCollection_Array1Test, Init)
+TEST(NCollection_Array1Test, Init)
 {
   NCollection_Array1<Standard_Integer> anArray(1, 5);
 
@@ -221,7 +209,7 @@ TEST_F(NCollection_Array1Test, Init)
   }
 }
 
-TEST_F(NCollection_Array1Test, SetValue)
+TEST(NCollection_Array1Test, SetValue)
 {
   NCollection_Array1<Standard_Integer> anArray(1, 5);
 
@@ -232,7 +220,7 @@ TEST_F(NCollection_Array1Test, SetValue)
   EXPECT_EQ(123, anArray(3));
 }
 
-TEST_F(NCollection_Array1Test, FirstLast)
+TEST(NCollection_Array1Test, FirstLast)
 {
   NCollection_Array1<Standard_Integer> anArray(5, 10);
 
@@ -251,7 +239,7 @@ TEST_F(NCollection_Array1Test, FirstLast)
   EXPECT_EQ(10101, anArray.Last());
 }
 
-TEST_F(NCollection_Array1Test, STLIteration)
+TEST(NCollection_Array1Test, STLIteration)
 {
   NCollection_Array1<Standard_Integer> anArray(1, 5);
   for (Standard_Integer i = anArray.Lower(); i <= anArray.Upper(); i++)
@@ -268,7 +256,7 @@ TEST_F(NCollection_Array1Test, STLIteration)
   }
 }
 
-TEST_F(NCollection_Array1Test, Resize)
+TEST(NCollection_Array1Test, Resize)
 {
   NCollection_Array1<Standard_Integer> anArray(1, 5);
   for (Standard_Integer i = anArray.Lower(); i <= anArray.Upper(); i++)
@@ -311,7 +299,7 @@ TEST_F(NCollection_Array1Test, Resize)
   }
 }
 
-TEST_F(NCollection_Array1Test, ChangeValue)
+TEST(NCollection_Array1Test, ChangeValue)
 {
   NCollection_Array1<Standard_Integer> anArray(1, 5);
   anArray.Init(42);
@@ -329,7 +317,7 @@ TEST_F(NCollection_Array1Test, ChangeValue)
   EXPECT_EQ(42, anArray(5));
 }
 
-TEST_F(NCollection_Array1Test, IteratorAccess)
+TEST(NCollection_Array1Test, IteratorAccess)
 {
   NCollection_Array1<Standard_Integer> anArray(1, 5);
   for (Standard_Integer i = 1; i <= 5; i++)
diff --git a/src/FoundationClasses/TKernel/GTests/NCollection_Array2_Test.cxx b/src/FoundationClasses/TKernel/GTests/NCollection_Array2_Test.cxx
new file mode 100644 (file)
index 0000000..9e88e76
--- /dev/null
@@ -0,0 +1,321 @@
+// Copyright (c) 2025 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <NCollection_Array2.hxx>
+#include <Standard_Integer.hxx>
+
+#include <gtest/gtest.h>
+
+// --- Constructor Tests ---
+
+TEST(NCollection_Array2Test, DefaultConstructor)
+{
+  NCollection_Array2<Standard_Integer> anArray;
+  EXPECT_EQ(0, anArray.Length());
+  EXPECT_EQ(0, anArray.NbRows());
+  EXPECT_EQ(0, anArray.NbColumns());
+}
+
+TEST(NCollection_Array2Test, ConstructorWithBounds)
+{
+  NCollection_Array2<Standard_Integer> anArray(1, 5, 1, 10);
+  EXPECT_EQ(50, anArray.Length());
+  EXPECT_EQ(5, anArray.NbRows());
+  EXPECT_EQ(10, anArray.NbColumns());
+  EXPECT_EQ(1, anArray.LowerRow());
+  EXPECT_EQ(5, anArray.UpperRow());
+  EXPECT_EQ(1, anArray.LowerCol());
+  EXPECT_EQ(10, anArray.UpperCol());
+}
+
+TEST(NCollection_Array2Test, ConstructorWithNegativeBounds)
+{
+  NCollection_Array2<Standard_Integer> anArray(-2, 2, -5, 5); // 5 rows, 11 cols
+  EXPECT_EQ(55, anArray.Length());
+  EXPECT_EQ(5, anArray.NbRows());
+  EXPECT_EQ(11, anArray.NbColumns());
+  EXPECT_EQ(-2, anArray.LowerRow());
+  EXPECT_EQ(2, anArray.UpperRow());
+  EXPECT_EQ(-5, anArray.LowerCol());
+  EXPECT_EQ(5, anArray.UpperCol());
+}
+
+// --- Data Access and Manipulation ---
+
+TEST(NCollection_Array2Test, ValueAccess)
+{
+  NCollection_Array2<Standard_Integer> anArray(1, 3, 1, 4);
+  for (Standard_Integer aRowIter = anArray.LowerRow(); aRowIter <= anArray.UpperRow(); ++aRowIter)
+  {
+    for (Standard_Integer aColIter = anArray.LowerCol(); aColIter <= anArray.UpperCol(); ++aColIter)
+    {
+      anArray.SetValue(aRowIter, aColIter, aRowIter * 100 + aColIter);
+    }
+  }
+
+  for (Standard_Integer aRowIter = anArray.LowerRow(); aRowIter <= anArray.UpperRow(); ++aRowIter)
+  {
+    for (Standard_Integer aColIter = anArray.LowerCol(); aColIter <= anArray.UpperCol(); ++aColIter)
+    {
+      EXPECT_EQ(aRowIter * 100 + aColIter, anArray.Value(aRowIter, aColIter));
+      EXPECT_EQ(aRowIter * 100 + aColIter, anArray(aRowIter, aColIter)); // Using operator()
+    }
+  }
+}
+
+TEST(NCollection_Array2Test, ChangeValueAccess)
+{
+  NCollection_Array2<Standard_Integer> anArray(0, 2, 0, 3);
+  for (Standard_Integer aRowIter = anArray.LowerRow(); aRowIter <= anArray.UpperRow(); ++aRowIter)
+  {
+    for (Standard_Integer aColIter = anArray.LowerCol(); aColIter <= anArray.UpperCol(); ++aColIter)
+    {
+      anArray.ChangeValue(aRowIter, aColIter) = aRowIter * 100 + aColIter;
+    }
+  }
+
+  // Verify initial values
+  EXPECT_EQ(102, anArray(1, 2));
+
+  // Modify a value
+  anArray.ChangeValue(1, 2) = 999;
+  EXPECT_EQ(999, anArray(1, 2));
+}
+
+TEST(NCollection_Array2Test, Init)
+{
+  NCollection_Array2<Standard_Integer> anArray(1, 5, 1, 5);
+  anArray.Init(42);
+  for (Standard_Integer aRowIter = anArray.LowerRow(); aRowIter <= anArray.UpperRow(); ++aRowIter)
+  {
+    for (Standard_Integer aColIter = anArray.LowerCol(); aColIter <= anArray.UpperCol(); ++aColIter)
+    {
+      EXPECT_EQ(42, anArray(aRowIter, aColIter));
+    }
+  }
+}
+
+// --- Copy and Move Semantics ---
+
+TEST(NCollection_Array2Test, CopyConstructor)
+{
+  NCollection_Array2<Standard_Integer> anArray1(1, 3, 1, 4);
+  anArray1.Init(123);
+
+  NCollection_Array2<Standard_Integer> anArray2(anArray1);
+
+  // Verify dimensions and data are copied
+  EXPECT_EQ(anArray1.Length(), anArray2.Length());
+  EXPECT_EQ(anArray1.NbRows(), anArray2.NbRows());
+  EXPECT_EQ(anArray1.NbColumns(), anArray2.NbColumns());
+  EXPECT_EQ(anArray1(2, 3), anArray2(2, 3));
+
+  // Modify original to ensure it was a deep copy
+  anArray1.SetValue(2, 3, 999);
+  EXPECT_EQ(123, anArray2(2, 3));
+  EXPECT_NE(anArray1(2, 3), anArray2(2, 3));
+}
+
+TEST(NCollection_Array2Test, AssignmentOperator)
+{
+  NCollection_Array2<Standard_Integer> anArray1(1, 3, 1, 4);
+  anArray1.Init(123);
+
+  NCollection_Array2<Standard_Integer> anArray2(1, 3, 1, 4);
+  anArray2.Init(0);
+
+  anArray2 = anArray1; // Assign
+
+  // Verify data is copied
+  EXPECT_EQ(123, anArray2(2, 3));
+
+  // Modify original to ensure it was a deep copy
+  anArray1.SetValue(2, 3, 999);
+  EXPECT_EQ(123, anArray2(2, 3));
+}
+
+TEST(NCollection_Array2Test, MoveConstructor)
+{
+  NCollection_Array2<Standard_Integer> anArray1(1, 5, 1, 10);
+  anArray1.SetValue(3, 7, 123);
+
+  // Move construct
+  NCollection_Array2<Standard_Integer> anArray2(std::move(anArray1));
+
+  // Verify new array has the data and dimensions
+  EXPECT_EQ(50, anArray2.Length());
+  EXPECT_EQ(5, anArray2.NbRows());
+  EXPECT_EQ(10, anArray2.NbColumns());
+  EXPECT_EQ(1, anArray2.LowerRow());
+  EXPECT_EQ(10, anArray2.UpperCol());
+  EXPECT_EQ(123, anArray2(3, 7));
+
+  // Verify the moved-from array is empty
+  EXPECT_EQ(0, anArray1.Length());
+  EXPECT_EQ(0, anArray1.NbRows());
+}
+
+TEST(NCollection_Array2Test, MoveAssignment)
+{
+  NCollection_Array2<Standard_Integer> anArray1(1, 5, 1, 10);
+  anArray1.SetValue(3, 7, 123);
+
+  NCollection_Array2<Standard_Integer> anArray2;
+  anArray2 = std::move(anArray1); // Move assignment
+
+  // Verify new array has the data and dimensions
+  EXPECT_EQ(50, anArray2.Length());
+  EXPECT_EQ(5, anArray2.NbRows());
+  EXPECT_EQ(123, anArray2(3, 7));
+
+  // Verify the moved-from array is empty
+  EXPECT_EQ(0, anArray1.Length());
+}
+
+// --- Resizing and Re-indexing ---
+
+TEST(NCollection_Array2Test, Resize)
+{
+  NCollection_Array2<Standard_Integer> anArray(1, 4, 1, 5); // 4x5 array
+  for (Standard_Integer aRowIter = 1; aRowIter <= 4; ++aRowIter)
+  {
+    for (Standard_Integer aColIter = 1; aColIter <= 5; ++aColIter)
+    {
+      anArray(aRowIter, aColIter) = aRowIter * 100 + aColIter;
+    }
+  }
+
+  // Resize to be larger, keeping data
+  anArray.Resize(0, 5, 0, 6, Standard_True); // New size 6x7
+
+  // Verify new dimensions
+  EXPECT_EQ(6, anArray.NbRows());
+  EXPECT_EQ(7, anArray.NbColumns());
+  EXPECT_EQ(0, anArray.LowerRow());
+  EXPECT_EQ(6, anArray.UpperCol());
+
+  // Verify original data is preserved in the correct locations
+  for (Standard_Integer aRowIter = 0; aRowIter <= 3; ++aRowIter)
+  {
+    for (Standard_Integer aColIter = 0; aColIter <= 4; ++aColIter)
+    {
+      EXPECT_EQ((aRowIter + 1) * 100 + (aColIter + 1), anArray(aRowIter, aColIter));
+    }
+  }
+}
+
+TEST(NCollection_Array2Test, ReIndex_UpdateBounds)
+{
+  NCollection_Array2<Standard_Integer> anArray(1, 5, 1, 10); // 5x10 array
+
+  // Test updating lower bounds
+  anArray.UpdateLowerRow(0);
+  anArray.UpdateLowerCol(0);
+  EXPECT_EQ(0, anArray.LowerRow());
+  EXPECT_EQ(4, anArray.UpperRow()); // 0 + 5 - 1
+  EXPECT_EQ(0, anArray.LowerCol());
+  EXPECT_EQ(9, anArray.UpperCol()); // 0 + 10 - 1
+  EXPECT_EQ(5, anArray.NbRows());   // Size should not change
+  EXPECT_EQ(10, anArray.NbColumns());
+
+  // Test updating upper bounds (which shifts the lower bounds)
+  anArray.UpdateUpperRow(10); // Request upper row to be 10
+  anArray.UpdateUpperCol(20); // Request upper col to be 20
+  EXPECT_EQ(10, anArray.UpperRow());
+  EXPECT_EQ(20, anArray.UpperCol());
+  EXPECT_EQ(6, anArray.LowerRow());  // Lower is now 10 - 5 + 1
+  EXPECT_EQ(11, anArray.LowerCol()); // Lower is now 20 - 10 + 1
+  EXPECT_EQ(5, anArray.NbRows());    // Size should not change
+  EXPECT_EQ(10, anArray.NbColumns());
+}
+
+// --- Iteration ---
+
+TEST(NCollection_Array2Test, STLIteration)
+{
+  NCollection_Array2<Standard_Integer> anArray(1, 2, 1, 3); // 2x3 array
+  for (Standard_Integer aRowIter = 1; aRowIter <= 2; ++aRowIter)
+  {
+    for (Standard_Integer aColIter = 1; aColIter <= 3; ++aColIter)
+    {
+      anArray(aRowIter, aColIter) = aRowIter * 10 + aColIter; // 11, 12, 13, 21, 22, 23
+    }
+  }
+
+  // Test range-based for loop
+  std::vector<Standard_Integer> aExpectedValues = {11, 12, 13, 21, 22, 23};
+  int                           anIndex         = 0;
+  for (const auto& aValue : anArray)
+  {
+    EXPECT_EQ(aExpectedValues[anIndex++], aValue);
+  }
+  EXPECT_EQ(6, anIndex); // Ensure all elements were visited
+}
+
+TEST(NCollection_Array2Test, Resize_ChangeShapeSameSize)
+{
+  // This test checks for data scrambling when resizing to a different shape
+  // with the same total number of elements.
+  NCollection_Array2<Standard_Integer> anArray(1, 4, 1, 6); // 4x6 = 24 elements
+  Standard_Integer                     anExpectedValue = 0;
+  for (Standard_Integer aRowIter = 1; aRowIter <= 4; ++aRowIter)
+  {
+    for (Standard_Integer aColIter = 1; aColIter <= 6; ++aColIter)
+    {
+      anArray(aRowIter, aColIter) = anExpectedValue++;
+    }
+  }
+
+  // Resize to 6x4 (24 elements), copying data
+  anArray.Resize(1, 6, 1, 4, Standard_True);
+
+  // Verify new dimensions
+  EXPECT_EQ(6, anArray.NbRows());
+  EXPECT_EQ(4, anArray.NbColumns());
+  EXPECT_EQ(24, anArray.Length());
+
+  // Verify the common 4x4 sub-matrix was not scrambled.
+  // This will fail if the copy logic in Resize is incorrect.
+  for (Standard_Integer anElemInd = anArray.Lower(); anElemInd < anArray.Lower() + 16; ++anElemInd)
+  {
+    EXPECT_EQ(anElemInd - anArray.Lower(),
+              static_cast<NCollection_Array1<Standard_Integer>&>(anArray).Value(anElemInd));
+  }
+}
+
+TEST(NCollection_Array2Test, ReIndex_Interference)
+{
+  // This test explicitly verifies that UpdateUpperRow modifies the LowerRow,
+  // showing how the separate update methods can interfere with each other.
+  NCollection_Array2<Standard_Integer> anArray(1, 10, 1, 1); // A 10x1 array
+  const Standard_Integer               anInitialNbRows = anArray.NbRows();
+
+  // 1. User sets a new lower bound.
+  anArray.UpdateLowerRow(5);
+  EXPECT_EQ(5, anArray.LowerRow());
+  EXPECT_EQ(14, anArray.UpperRow()); // Upper bound is now 5 + 10 - 1
+
+  // 2. User then sets a new upper bound, expecting the lower bound to stay at 5.
+  anArray.UpdateUpperRow(12);
+
+  // 3. Verify the final state.
+  EXPECT_EQ(12, anArray.UpperRow()); // The upper bound is set as requested.
+
+  // Verify that the lower bound was changed to accommodate the new upper bound,
+  // undoing the previous call to UpdateLowerRow.
+  EXPECT_EQ(3, anArray.LowerRow()); // Lower bound is now 12 - 10 + 1 = 3
+  EXPECT_NE(5, anArray.LowerRow()); // It is no longer 5.
+
+  // The total number of rows should never change during these operations.
+  EXPECT_EQ(anInitialNbRows, anArray.NbRows());
+}
\ No newline at end of file
index 6659d8d13b6b88cb418ef2dae5dedd5aad86063c..374795b087e592fe39b1c05b861ad1b9acf396b7 100644 (file)
@@ -171,7 +171,10 @@ public:
         myPointer(theOther.myPointer),
         myIsOwner(theOther.myIsOwner)
   {
-    theOther.myIsOwner = false;
+    theOther.myIsOwner    = false;
+    theOther.myPointer    = nullptr;
+    theOther.mySize       = 0;
+    theOther.myLowerBound = 1;
   }
 
   virtual ~NCollection_Array1()
@@ -241,11 +244,14 @@ public:
       destroy(myPointer, 0, mySize);
       myAllocator.deallocate(myPointer, mySize);
     }
-    myLowerBound       = theOther.myLowerBound;
-    mySize             = theOther.mySize;
-    myPointer          = theOther.myPointer;
-    myIsOwner          = theOther.myIsOwner;
-    theOther.myIsOwner = false;
+    myLowerBound          = theOther.myLowerBound;
+    mySize                = theOther.mySize;
+    myPointer             = theOther.myPointer;
+    myIsOwner             = theOther.myIsOwner;
+    theOther.myIsOwner    = false;
+    theOther.myPointer    = nullptr;
+    theOther.mySize       = 0;
+    theOther.myLowerBound = 1;
     return *this;
   }
 
index 74c53ee13e0765d14a6c61cacda53c8a94e3189f..a0089275949ad957c796cb6ff5de40cf00df76f5 100644 (file)
@@ -146,6 +146,10 @@ public:
         myLowerCol(theOther.LowerCol()),
         mySizeCol(theOther.NbColumns())
   {
+    theOther.myLowerRow = 1;
+    theOther.mySizeRow  = 0;
+    theOther.myLowerCol = 1;
+    theOther.mySizeCol  = 0;
   }
 
   //! C array-based constructor
@@ -195,6 +199,24 @@ public:
   //! UpperCol
   Standard_Integer UpperCol() const { return myLowerCol + static_cast<int>(mySizeCol) - 1; }
 
+  //! Updates lower row
+  void UpdateLowerRow(const Standard_Integer theLowerRow) { myLowerRow = theLowerRow; }
+
+  //! Updates lower column
+  void UpdateLowerCol(const Standard_Integer theLowerCol) { myLowerCol = theLowerCol; }
+
+  //! Updates upper row
+  void UpdateUpperRow(const Standard_Integer theUpperRow)
+  {
+    myLowerRow = myLowerRow - UpperRow() + theUpperRow;
+  }
+
+  //! Updates upper column
+  void UpdateUpperCol(const Standard_Integer theUpperCol)
+  {
+    myLowerCol = myLowerCol - UpperCol() + theUpperCol;
+  }
+
   //! Assignment
   NCollection_Array2& Assign(const NCollection_Array2& theOther)
   {
@@ -203,6 +225,7 @@ public:
       return *this;
     }
     NCollection_Array1<TheItemType>::Assign(theOther);
+    // Current implementation disable changing bounds by assigning
     return *this;
   }
 
@@ -216,10 +239,14 @@ public:
       return *this;
     }
     NCollection_Array1<TheItemType>::Move(theOther);
-    myLowerRow = theOther.myLowerRow;
-    mySizeRow  = theOther.mySizeRow;
-    myLowerCol = theOther.myLowerCol;
-    mySizeCol  = theOther.mySizeCol;
+    myLowerRow          = theOther.myLowerRow;
+    mySizeRow           = theOther.mySizeRow;
+    myLowerCol          = theOther.myLowerCol;
+    mySizeCol           = theOther.mySizeCol;
+    theOther.myLowerRow = 1;
+    theOther.mySizeRow  = 0;
+    theOther.myLowerCol = 1;
+    theOther.mySizeCol  = 0;
     return *this;
   }
 
@@ -296,31 +323,34 @@ public:
   {
     Standard_RangeError_Raise_if(theRowUpper < theRowLower || theColUpper < theColLower,
                                  "NCollection_Array2::Resize");
-    myLowerRow = theRowLower;
-    myLowerCol = theColLower;
     if (!theToCopyData)
     {
       NCollection_Array1<TheItemType>::Resize(
         BeginPosition(theRowLower, theRowUpper, theColLower, theColUpper),
         LastPosition(theRowLower, theRowUpper, theColLower, theColUpper),
         false);
-      mySizeRow = theRowUpper - theRowLower + 1;
-      mySizeCol = theColUpper - theColLower + 1;
+      mySizeRow  = theRowUpper - theRowLower + 1;
+      mySizeCol  = theColUpper - theColLower + 1;
+      myLowerRow = theRowLower;
+      myLowerCol = theColLower;
       return;
     }
-    NCollection_Array1<TheItemType> aTmpMovedCopy(std::move(*this));
+    const size_t aNewNbRows    = theRowUpper - theRowLower + 1;
+    const size_t aNewNbCols    = theColUpper - theColLower + 1;
+    const size_t aNbRowsToCopy = std::min<size_t>(mySizeRow, aNewNbRows);
+    const size_t aNbColsToCopy = std::min<size_t>(mySizeCol, aNewNbCols);
+
+    NCollection_Array2<TheItemType> aTmpMovedCopy(std::move(*this));
     TheItemType*                    anOldPointer = &aTmpMovedCopy.ChangeFirst();
     NCollection_Array1<TheItemType>::Resize(
       BeginPosition(theRowLower, theRowUpper, theColLower, theColUpper),
       LastPosition(theRowLower, theRowUpper, theColLower, theColUpper),
       false);
-    const size_t aNewNbRows    = theRowUpper - theRowLower + 1;
-    const size_t aNewNbCols    = theColUpper - theColLower + 1;
-    const size_t aNbRowsToCopy = std::min<size_t>(mySizeRow, aNewNbRows);
-    const size_t aNbColsToCopy = std::min<size_t>(mySizeCol, aNewNbCols);
-    mySizeRow                  = aNewNbRows;
-    mySizeCol                  = aNewNbCols;
-    size_t aOldInter           = 0;
+    mySizeRow        = aNewNbRows;
+    mySizeCol        = aNewNbCols;
+    myLowerRow       = theRowLower;
+    myLowerCol       = theColLower;
+    size_t aOldInter = 0;
     for (size_t aRowIter = 0; aRowIter < aNbRowsToCopy; ++aRowIter)
     {
       for (size_t aColIter = 0; aColIter < aNbColsToCopy; ++aColIter)