diff --git a/src/FoundationClasses/TKMath/GTests/math_Vector_Test.cxx b/src/FoundationClasses/TKMath/GTests/math_Vector_Test.cxx index 0881c96847..d1d56cbe13 100644 --- a/src/FoundationClasses/TKMath/GTests/math_Vector_Test.cxx +++ b/src/FoundationClasses/TKMath/GTests/math_Vector_Test.cxx @@ -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(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(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(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(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(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(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(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(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(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(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(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(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(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(i)); + } +} diff --git a/src/FoundationClasses/TKMath/math/math_VectorBase.hxx b/src/FoundationClasses/TKMath/math/math_VectorBase.hxx index a38afd1a73..c421c431aa 100644 --- a/src/FoundationClasses/TKMath/math/math_VectorBase.hxx +++ b/src/FoundationClasses/TKMath/math/math_VectorBase.hxx @@ -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& 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); diff --git a/src/FoundationClasses/TKMath/math/math_VectorBase.lxx b/src/FoundationClasses/TKMath/math/math_VectorBase.lxx index 6e0314c010..9590c9d546 100644 --- a/src/FoundationClasses/TKMath/math/math_VectorBase.lxx +++ b/src/FoundationClasses/TKMath/math/math_VectorBase.lxx @@ -590,3 +590,33 @@ void math_VectorBase::Dump(Standard_OStream& theO) const theO << "math_Vector(" << Index << ") = " << Array(Index) << "\n"; } } + +template +void math_VectorBase::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(*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(*myBuffer.data(), theLower, theUpper); + } + else + { + // Stack -> Heap or Heap -> Heap: Array.Resize handles data copy + Array.Resize(theLower, theUpper, Standard_True); + } +}