mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-05-10 09:30:48 +08:00
Modeling - Implementation for math_Vector Resize functionality (#957)
math_VectorBase can be used with both stack and heap storage and resized when needed. This is not often required, but when it is, the Resize method allows to do it efficiently, preserving existing data and optimizing memory usage.
This commit is contained in:
@@ -701,3 +701,163 @@ TEST(MathVectorTest, MoveSemantics)
|
||||
|
||||
EXPECT_EQ(aVecAssign1.Length(), 0);
|
||||
}
|
||||
|
||||
// Tests for Resize operation
|
||||
TEST(MathVectorTest, Resize_StackToStack_SameSize)
|
||||
{
|
||||
// Small vector that fits in stack buffer (THE_BUFFER_SIZE = 32)
|
||||
math_Vector aVec(1, 10);
|
||||
for (Standard_Integer i = 1; i <= 10; ++i)
|
||||
{
|
||||
aVec(i) = static_cast<Standard_Real>(i);
|
||||
}
|
||||
|
||||
// Resize to same size - data should be preserved
|
||||
aVec.Resize(10);
|
||||
|
||||
EXPECT_EQ(aVec.Length(), 10);
|
||||
EXPECT_EQ(aVec.Lower(), 1);
|
||||
EXPECT_EQ(aVec.Upper(), 10);
|
||||
for (Standard_Integer i = 1; i <= 10; ++i)
|
||||
{
|
||||
EXPECT_DOUBLE_EQ(aVec(i), static_cast<Standard_Real>(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MathVectorTest, Resize_StackToStack_Grow)
|
||||
{
|
||||
// Small vector
|
||||
math_Vector aVec(1, 5);
|
||||
for (Standard_Integer i = 1; i <= 5; ++i)
|
||||
{
|
||||
aVec(i) = static_cast<Standard_Real>(i * 10);
|
||||
}
|
||||
|
||||
// Grow but still within stack buffer
|
||||
aVec.Resize(20);
|
||||
|
||||
EXPECT_EQ(aVec.Length(), 20);
|
||||
EXPECT_EQ(aVec.Lower(), 1);
|
||||
EXPECT_EQ(aVec.Upper(), 20);
|
||||
|
||||
// Original data should be preserved
|
||||
for (Standard_Integer i = 1; i <= 5; ++i)
|
||||
{
|
||||
EXPECT_DOUBLE_EQ(aVec(i), static_cast<Standard_Real>(i * 10));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MathVectorTest, Resize_StackToStack_Shrink)
|
||||
{
|
||||
// Small vector
|
||||
math_Vector aVec(1, 20);
|
||||
for (Standard_Integer i = 1; i <= 20; ++i)
|
||||
{
|
||||
aVec(i) = static_cast<Standard_Real>(i);
|
||||
}
|
||||
|
||||
// Shrink but still within stack buffer
|
||||
aVec.Resize(10);
|
||||
|
||||
EXPECT_EQ(aVec.Length(), 10);
|
||||
EXPECT_EQ(aVec.Lower(), 1);
|
||||
EXPECT_EQ(aVec.Upper(), 10);
|
||||
|
||||
// Data within new range should be preserved
|
||||
for (Standard_Integer i = 1; i <= 10; ++i)
|
||||
{
|
||||
EXPECT_DOUBLE_EQ(aVec(i), static_cast<Standard_Real>(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MathVectorTest, Resize_StackToHeap)
|
||||
{
|
||||
// Small vector that fits in stack
|
||||
math_Vector aVec(1, 20);
|
||||
for (Standard_Integer i = 1; i <= 20; ++i)
|
||||
{
|
||||
aVec(i) = static_cast<Standard_Real>(i);
|
||||
}
|
||||
|
||||
// Resize to larger than stack buffer (>32)
|
||||
aVec.Resize(50);
|
||||
|
||||
EXPECT_EQ(aVec.Length(), 50);
|
||||
EXPECT_EQ(aVec.Lower(), 1);
|
||||
EXPECT_EQ(aVec.Upper(), 50);
|
||||
|
||||
// Original data should be preserved
|
||||
for (Standard_Integer i = 1; i <= 20; ++i)
|
||||
{
|
||||
EXPECT_DOUBLE_EQ(aVec(i), static_cast<Standard_Real>(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MathVectorTest, Resize_HeapToStack)
|
||||
{
|
||||
// Large vector on heap
|
||||
math_Vector aVec(1, 50);
|
||||
for (Standard_Integer i = 1; i <= 50; ++i)
|
||||
{
|
||||
aVec(i) = static_cast<Standard_Real>(i);
|
||||
}
|
||||
|
||||
// Resize to fit in stack buffer
|
||||
aVec.Resize(20);
|
||||
|
||||
EXPECT_EQ(aVec.Length(), 20);
|
||||
EXPECT_EQ(aVec.Lower(), 1);
|
||||
EXPECT_EQ(aVec.Upper(), 20);
|
||||
|
||||
// Data within new range should be preserved
|
||||
for (Standard_Integer i = 1; i <= 20; ++i)
|
||||
{
|
||||
EXPECT_DOUBLE_EQ(aVec(i), static_cast<Standard_Real>(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MathVectorTest, Resize_HeapToHeap)
|
||||
{
|
||||
// Large vector on heap
|
||||
math_Vector aVec(1, 50);
|
||||
for (Standard_Integer i = 1; i <= 50; ++i)
|
||||
{
|
||||
aVec(i) = static_cast<Standard_Real>(i);
|
||||
}
|
||||
|
||||
// Resize to different heap size
|
||||
aVec.Resize(100);
|
||||
|
||||
EXPECT_EQ(aVec.Length(), 100);
|
||||
EXPECT_EQ(aVec.Lower(), 1);
|
||||
EXPECT_EQ(aVec.Upper(), 100);
|
||||
|
||||
// Original data should be preserved
|
||||
for (Standard_Integer i = 1; i <= 50; ++i)
|
||||
{
|
||||
EXPECT_DOUBLE_EQ(aVec(i), static_cast<Standard_Real>(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MathVectorTest, Resize_NegativeLowerBound)
|
||||
{
|
||||
// Vector with negative lower bound
|
||||
math_Vector aVec(-5, 5);
|
||||
for (Standard_Integer i = -5; i <= 5; ++i)
|
||||
{
|
||||
aVec(i) = static_cast<Standard_Real>(i);
|
||||
}
|
||||
|
||||
// Resize - lower bound preserved
|
||||
aVec.Resize(8);
|
||||
|
||||
EXPECT_EQ(aVec.Length(), 8);
|
||||
EXPECT_EQ(aVec.Lower(), -5);
|
||||
EXPECT_EQ(aVec.Upper(), 2);
|
||||
|
||||
// Original data should be preserved
|
||||
for (Standard_Integer i = -5; i <= 2; ++i)
|
||||
{
|
||||
EXPECT_DOUBLE_EQ(aVec(i), static_cast<Standard_Real>(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,6 +306,19 @@ public:
|
||||
//! Is used to redefine the operator <<.
|
||||
inline void Dump(Standard_OStream& theO) const;
|
||||
|
||||
//! Returns the underlying array for interoperability with legacy APIs.
|
||||
//! Allows passing math_Vector data to functions expecting NCollection_Array1.
|
||||
const NCollection_Array1<TheItemType>& Array1() const { return Array; }
|
||||
|
||||
//! Resizes the vector to a new size, keeping the same lower bound.
|
||||
//! Existing data within the new range is preserved.
|
||||
//! The method optimizes memory usage:
|
||||
//! - If new size fits in stack buffer (<=32), uses stack allocation
|
||||
//! - If new size requires heap and was already on heap, resizes in place
|
||||
//! - Transitions between stack and heap as needed
|
||||
//! @param theSize new size of the vector
|
||||
inline void Resize(const Standard_Integer theSize);
|
||||
|
||||
friend inline Standard_OStream& operator<<(Standard_OStream& theO, const math_VectorBase& theVec)
|
||||
{
|
||||
theVec.Dump(theO);
|
||||
|
||||
@@ -590,3 +590,33 @@ void math_VectorBase<TheItemType>::Dump(Standard_OStream& theO) const
|
||||
theO << "math_Vector(" << Index << ") = " << Array(Index) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TheItemType>
|
||||
void math_VectorBase<TheItemType>::Resize(const Standard_Integer theSize)
|
||||
{
|
||||
const Standard_Integer theLower = Array.Lower();
|
||||
const Standard_Integer theUpper = theLower + theSize - 1;
|
||||
const Standard_Boolean aNewFitsStack = theSize <= THE_BUFFER_SIZE;
|
||||
const Standard_Boolean aWasOnStack = !Array.IsDeletable();
|
||||
|
||||
if (aWasOnStack && aNewFitsStack)
|
||||
{
|
||||
// Stack -> Stack: data is already in myBuffer, just update Array bounds
|
||||
Array = NCollection_Array1<TheItemType>(*myBuffer.data(), theLower, theUpper);
|
||||
}
|
||||
else if (aNewFitsStack)
|
||||
{
|
||||
// Heap -> Stack: copy data to stack buffer
|
||||
const Standard_Integer aCopyLen = std::min(Array.Length(), theSize);
|
||||
for (Standard_Integer i = 0; i < aCopyLen; ++i)
|
||||
{
|
||||
myBuffer[i] = Array.Value(theLower + i);
|
||||
}
|
||||
Array = NCollection_Array1<TheItemType>(*myBuffer.data(), theLower, theUpper);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stack -> Heap or Heap -> Heap: Array.Resize handles data copy
|
||||
Array.Resize(theLower, theUpper, Standard_True);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user