- 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
set(OCCT_TKMath_GTests_FILES
Bnd_BoundSortBox_Test.cxx
ElCLib_Test.cxx
+ math_DoubleTab_Test.cxx
math_Matrix_Test.cxx
)
--- /dev/null
+// 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);
+}
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
+++ /dev/null
-// 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;
-}
#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
+++ /dev/null
-// 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)));
-}
//! 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);
}
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
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
#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;
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);
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);
EXPECT_EQ(2, anArray.Upper());
}
-TEST_F(NCollection_Array1Test, AssignmentValue)
+TEST(NCollection_Array1Test, AssignmentValue)
{
NCollection_Array1<Standard_Integer> anArray(1, 5);
}
}
-TEST_F(NCollection_Array1Test, CopyConstructor)
+TEST(NCollection_Array1Test, CopyConstructor)
{
NCollection_Array1<Standard_Integer> anArray1(1, 5);
EXPECT_NE(anArray1(3), anArray2(3));
}
-TEST_F(NCollection_Array1Test, ValueAccess)
+TEST(NCollection_Array1Test, ValueAccess)
{
NCollection_Array1<Standard_Integer> anArray(1, 5);
}
}
-TEST_F(NCollection_Array1Test, ChangeValueAccess)
+TEST(NCollection_Array1Test, ChangeValueAccess)
{
NCollection_Array1<Standard_Integer> anArray(1, 5);
}
}
-TEST_F(NCollection_Array1Test, AssignmentOperator)
+TEST(NCollection_Array1Test, AssignmentOperator)
{
NCollection_Array1<Standard_Integer> anArray1(1, 5);
}
}
-TEST_F(NCollection_Array1Test, Move)
+TEST(NCollection_Array1Test, Move)
{
NCollection_Array1<Standard_Integer> anArray1(1, 5);
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);
}
}
-TEST_F(NCollection_Array1Test, SetValue)
+TEST(NCollection_Array1Test, SetValue)
{
NCollection_Array1<Standard_Integer> anArray(1, 5);
EXPECT_EQ(123, anArray(3));
}
-TEST_F(NCollection_Array1Test, FirstLast)
+TEST(NCollection_Array1Test, FirstLast)
{
NCollection_Array1<Standard_Integer> anArray(5, 10);
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++)
}
}
-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++)
}
}
-TEST_F(NCollection_Array1Test, ChangeValue)
+TEST(NCollection_Array1Test, ChangeValue)
{
NCollection_Array1<Standard_Integer> anArray(1, 5);
anArray.Init(42);
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++)
--- /dev/null
+// 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
myPointer(theOther.myPointer),
myIsOwner(theOther.myIsOwner)
{
- theOther.myIsOwner = false;
+ theOther.myIsOwner = false;
+ theOther.myPointer = nullptr;
+ theOther.mySize = 0;
+ theOther.myLowerBound = 1;
}
virtual ~NCollection_Array1()
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;
}
myLowerCol(theOther.LowerCol()),
mySizeCol(theOther.NbColumns())
{
+ theOther.myLowerRow = 1;
+ theOther.mySizeRow = 0;
+ theOther.myLowerCol = 1;
+ theOther.mySizeCol = 0;
}
//! C array-based constructor
//! 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)
{
return *this;
}
NCollection_Array1<TheItemType>::Assign(theOther);
+ // Current implementation disable changing bounds by assigning
return *this;
}
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;
}
{
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)