mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-05-10 01:20:50 +08:00
Foundation Classes - Add Emplace methods to NCollection containers (#1035)
Add in-place construction support to sequential and array containers, following the pattern already established in map containers. New methods added: - NCollection_List: EmplaceAppend, EmplacePrepend, EmplaceBefore, EmplaceAfter - NCollection_Sequence: EmplaceAppend, EmplacePrepend, EmplaceAfter, EmplaceBefore - NCollection_DynamicArray: EmplaceAppend, EmplaceValue - NCollection_Array1: EmplaceValue - NCollection_Array2: EmplaceValue NCollection_Sequence::Node class extended with in-place constructor to support the new Emplace methods. All methods use perfect forwarding to construct elements in-place, avoiding unnecessary copies or moves. This is particularly useful for: - Types with expensive copy/move operations - Types with multiple constructor arguments - Move-only types (non-copyable) Added corresponding unit tests for all new methods.
This commit is contained in:
@@ -413,3 +413,65 @@ TEST(NCollection_Array1Test, STLAlgorithmCompatibility_Sort)
|
||||
|
||||
EXPECT_TRUE(std::equal(anArray.begin(), anArray.end(), aVector.begin()));
|
||||
}
|
||||
|
||||
// Helper struct for testing in-place construction with multiple arguments
|
||||
struct Array1MultiArgType
|
||||
{
|
||||
int myA;
|
||||
double myB;
|
||||
|
||||
Array1MultiArgType()
|
||||
: myA(0),
|
||||
myB(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
Array1MultiArgType(int theA, double theB)
|
||||
: myA(theA),
|
||||
myB(theB)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
TEST(NCollection_Array1Test, EmplaceValue)
|
||||
{
|
||||
NCollection_Array1<Array1MultiArgType> anArray(1, 5);
|
||||
|
||||
// Test EmplaceValue with multiple constructor arguments
|
||||
Array1MultiArgType& aRef1 = anArray.EmplaceValue(1, 42, 3.14);
|
||||
EXPECT_EQ(42, aRef1.myA);
|
||||
EXPECT_NEAR(3.14, aRef1.myB, 1e-10);
|
||||
|
||||
Array1MultiArgType& aRef2 = anArray.EmplaceValue(3, 100, 2.71);
|
||||
EXPECT_EQ(100, aRef2.myA);
|
||||
EXPECT_NEAR(2.71, aRef2.myB, 1e-10);
|
||||
|
||||
// Verify the values are in the array
|
||||
EXPECT_EQ(42, anArray(1).myA);
|
||||
EXPECT_EQ(100, anArray(3).myA);
|
||||
|
||||
// Verify other elements are default-constructed
|
||||
EXPECT_EQ(0, anArray(2).myA);
|
||||
EXPECT_EQ(0, anArray(4).myA);
|
||||
EXPECT_EQ(0, anArray(5).myA);
|
||||
}
|
||||
|
||||
TEST(NCollection_Array1Test, EmplaceValue_ReplacesExisting)
|
||||
{
|
||||
NCollection_Array1<Array1MultiArgType> anArray(1, 3);
|
||||
|
||||
// Set initial values
|
||||
anArray.EmplaceValue(1, 10, 1.0);
|
||||
anArray.EmplaceValue(2, 20, 2.0);
|
||||
anArray.EmplaceValue(3, 30, 3.0);
|
||||
|
||||
// Replace value at index 2
|
||||
Array1MultiArgType& aRef = anArray.EmplaceValue(2, 200, 20.0);
|
||||
EXPECT_EQ(200, aRef.myA);
|
||||
EXPECT_NEAR(20.0, aRef.myB, 1e-10);
|
||||
|
||||
// Verify other values unchanged
|
||||
EXPECT_EQ(10, anArray(1).myA);
|
||||
EXPECT_EQ(200, anArray(2).myA);
|
||||
EXPECT_EQ(30, anArray(3).myA);
|
||||
}
|
||||
|
||||
@@ -318,4 +318,67 @@ TEST(NCollection_Array2Test, ReIndex_Interference)
|
||||
|
||||
// The total number of rows should never change during these operations.
|
||||
EXPECT_EQ(anInitialNbRows, anArray.NbRows());
|
||||
}
|
||||
|
||||
// Helper struct for testing in-place construction with multiple arguments
|
||||
struct Array2MultiArgType
|
||||
{
|
||||
int myA;
|
||||
double myB;
|
||||
|
||||
Array2MultiArgType()
|
||||
: myA(0),
|
||||
myB(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
Array2MultiArgType(int theA, double theB)
|
||||
: myA(theA),
|
||||
myB(theB)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
TEST(NCollection_Array2Test, EmplaceValue)
|
||||
{
|
||||
NCollection_Array2<Array2MultiArgType> anArray(1, 3, 1, 4);
|
||||
|
||||
// Test EmplaceValue with multiple constructor arguments
|
||||
Array2MultiArgType& aRef1 = anArray.EmplaceValue(1, 1, 42, 3.14);
|
||||
EXPECT_EQ(42, aRef1.myA);
|
||||
EXPECT_NEAR(3.14, aRef1.myB, 1e-10);
|
||||
|
||||
Array2MultiArgType& aRef2 = anArray.EmplaceValue(2, 3, 100, 2.71);
|
||||
EXPECT_EQ(100, aRef2.myA);
|
||||
EXPECT_NEAR(2.71, aRef2.myB, 1e-10);
|
||||
|
||||
// Verify the values are in the array
|
||||
EXPECT_EQ(42, anArray(1, 1).myA);
|
||||
EXPECT_EQ(100, anArray(2, 3).myA);
|
||||
|
||||
// Verify other elements are default-constructed
|
||||
EXPECT_EQ(0, anArray(1, 2).myA);
|
||||
EXPECT_EQ(0, anArray(3, 4).myA);
|
||||
}
|
||||
|
||||
TEST(NCollection_Array2Test, EmplaceValue_ReplacesExisting)
|
||||
{
|
||||
NCollection_Array2<Array2MultiArgType> anArray(1, 2, 1, 2);
|
||||
|
||||
// Set initial values
|
||||
anArray.EmplaceValue(1, 1, 11, 1.1);
|
||||
anArray.EmplaceValue(1, 2, 12, 1.2);
|
||||
anArray.EmplaceValue(2, 1, 21, 2.1);
|
||||
anArray.EmplaceValue(2, 2, 22, 2.2);
|
||||
|
||||
// Replace value at (1, 2)
|
||||
Array2MultiArgType& aRef = anArray.EmplaceValue(1, 2, 120, 12.0);
|
||||
EXPECT_EQ(120, aRef.myA);
|
||||
EXPECT_NEAR(12.0, aRef.myB, 1e-10);
|
||||
|
||||
// Verify other values unchanged
|
||||
EXPECT_EQ(11, anArray(1, 1).myA);
|
||||
EXPECT_EQ(120, anArray(1, 2).myA);
|
||||
EXPECT_EQ(21, anArray(2, 1).myA);
|
||||
EXPECT_EQ(22, anArray(2, 2).myA);
|
||||
}
|
||||
@@ -484,4 +484,149 @@ TEST_F(NCollection_ListTest, OCC25348_AssignDoesNotChangeAllocator)
|
||||
EXPECT_EQ(1, aList1.Size());
|
||||
EXPECT_EQ(i, aList1.First());
|
||||
}
|
||||
}
|
||||
|
||||
// Helper struct for testing in-place construction with multiple arguments
|
||||
struct MultiArgType
|
||||
{
|
||||
int myA;
|
||||
double myB;
|
||||
|
||||
MultiArgType(int theA, double theB)
|
||||
: myA(theA),
|
||||
myB(theB)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Helper struct for testing move-only types
|
||||
struct MoveOnlyType
|
||||
{
|
||||
int myValue;
|
||||
|
||||
explicit MoveOnlyType(int theValue)
|
||||
: myValue(theValue)
|
||||
{
|
||||
}
|
||||
|
||||
MoveOnlyType(MoveOnlyType&& theOther) noexcept
|
||||
: myValue(theOther.myValue)
|
||||
{
|
||||
theOther.myValue = 0;
|
||||
}
|
||||
|
||||
MoveOnlyType& operator=(MoveOnlyType&& theOther) noexcept
|
||||
{
|
||||
myValue = theOther.myValue;
|
||||
theOther.myValue = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MoveOnlyType(const MoveOnlyType&) = delete;
|
||||
MoveOnlyType& operator=(const MoveOnlyType&) = delete;
|
||||
};
|
||||
|
||||
TEST_F(NCollection_ListTest, EmplaceAppend)
|
||||
{
|
||||
NCollection_List<MultiArgType> aList;
|
||||
|
||||
// Test EmplaceAppend with multiple constructor arguments
|
||||
MultiArgType& aRef1 = aList.EmplaceAppend(42, 3.14);
|
||||
EXPECT_EQ(42, aRef1.myA);
|
||||
EXPECT_NEAR(3.14, aRef1.myB, 1e-10);
|
||||
EXPECT_EQ(1, aList.Size());
|
||||
|
||||
MultiArgType& aRef2 = aList.EmplaceAppend(100, 2.71);
|
||||
EXPECT_EQ(100, aRef2.myA);
|
||||
EXPECT_NEAR(2.71, aRef2.myB, 1e-10);
|
||||
EXPECT_EQ(2, aList.Size());
|
||||
|
||||
// Verify the order
|
||||
EXPECT_EQ(42, aList.First().myA);
|
||||
EXPECT_EQ(100, aList.Last().myA);
|
||||
}
|
||||
|
||||
TEST_F(NCollection_ListTest, EmplacePrepend)
|
||||
{
|
||||
NCollection_List<MultiArgType> aList;
|
||||
|
||||
// Test EmplacePrepend with multiple constructor arguments
|
||||
MultiArgType& aRef1 = aList.EmplacePrepend(42, 3.14);
|
||||
EXPECT_EQ(42, aRef1.myA);
|
||||
EXPECT_NEAR(3.14, aRef1.myB, 1e-10);
|
||||
EXPECT_EQ(1, aList.Size());
|
||||
|
||||
MultiArgType& aRef2 = aList.EmplacePrepend(100, 2.71);
|
||||
EXPECT_EQ(100, aRef2.myA);
|
||||
EXPECT_NEAR(2.71, aRef2.myB, 1e-10);
|
||||
EXPECT_EQ(2, aList.Size());
|
||||
|
||||
// Verify the order (prepended items should be at the front)
|
||||
EXPECT_EQ(100, aList.First().myA);
|
||||
EXPECT_EQ(42, aList.Last().myA);
|
||||
}
|
||||
|
||||
TEST_F(NCollection_ListTest, EmplaceBefore)
|
||||
{
|
||||
NCollection_List<MultiArgType> aList;
|
||||
aList.EmplaceAppend(10, 1.0);
|
||||
aList.EmplaceAppend(30, 3.0);
|
||||
|
||||
// Get iterator to second element
|
||||
NCollection_List<MultiArgType>::Iterator anIter(aList);
|
||||
anIter.Next();
|
||||
|
||||
// Emplace before the second element
|
||||
MultiArgType& aRef = aList.EmplaceBefore(anIter, 20, 2.0);
|
||||
EXPECT_EQ(20, aRef.myA);
|
||||
EXPECT_NEAR(2.0, aRef.myB, 1e-10);
|
||||
|
||||
// Verify the order
|
||||
EXPECT_EQ(3, aList.Size());
|
||||
NCollection_List<MultiArgType>::Iterator aCheckIter(aList);
|
||||
EXPECT_EQ(10, aCheckIter.Value().myA);
|
||||
aCheckIter.Next();
|
||||
EXPECT_EQ(20, aCheckIter.Value().myA);
|
||||
aCheckIter.Next();
|
||||
EXPECT_EQ(30, aCheckIter.Value().myA);
|
||||
}
|
||||
|
||||
TEST_F(NCollection_ListTest, EmplaceAfter)
|
||||
{
|
||||
NCollection_List<MultiArgType> aList;
|
||||
aList.EmplaceAppend(10, 1.0);
|
||||
aList.EmplaceAppend(30, 3.0);
|
||||
|
||||
// Get iterator to first element
|
||||
NCollection_List<MultiArgType>::Iterator anIter(aList);
|
||||
|
||||
// Emplace after the first element
|
||||
MultiArgType& aRef = aList.EmplaceAfter(anIter, 20, 2.0);
|
||||
EXPECT_EQ(20, aRef.myA);
|
||||
EXPECT_NEAR(2.0, aRef.myB, 1e-10);
|
||||
|
||||
// Verify the order
|
||||
EXPECT_EQ(3, aList.Size());
|
||||
NCollection_List<MultiArgType>::Iterator aCheckIter(aList);
|
||||
EXPECT_EQ(10, aCheckIter.Value().myA);
|
||||
aCheckIter.Next();
|
||||
EXPECT_EQ(20, aCheckIter.Value().myA);
|
||||
aCheckIter.Next();
|
||||
EXPECT_EQ(30, aCheckIter.Value().myA);
|
||||
}
|
||||
|
||||
TEST_F(NCollection_ListTest, EmplaceWithMoveOnlyType)
|
||||
{
|
||||
NCollection_List<MoveOnlyType> aList;
|
||||
|
||||
// Test EmplaceAppend with move-only type
|
||||
MoveOnlyType& aRef1 = aList.EmplaceAppend(42);
|
||||
EXPECT_EQ(42, aRef1.myValue);
|
||||
|
||||
MoveOnlyType& aRef2 = aList.EmplacePrepend(100);
|
||||
EXPECT_EQ(100, aRef2.myValue);
|
||||
|
||||
EXPECT_EQ(2, aList.Size());
|
||||
EXPECT_EQ(100, aList.First().myValue);
|
||||
EXPECT_EQ(42, aList.Last().myValue);
|
||||
}
|
||||
@@ -459,4 +459,157 @@ TEST(NCollection_SequenceTest, OCC26448_PrependEmptySequence)
|
||||
aTSeq1.Prepend(aTSeq2); // Prepend empty sequence
|
||||
EXPECT_EQ(aTSeq1.Size(), 1);
|
||||
EXPECT_DOUBLE_EQ(aTSeq1.First(), 11.0);
|
||||
}
|
||||
|
||||
// Helper struct for testing in-place construction with multiple arguments
|
||||
struct SeqMultiArgType
|
||||
{
|
||||
int myA;
|
||||
double myB;
|
||||
|
||||
SeqMultiArgType(int theA, double theB)
|
||||
: myA(theA),
|
||||
myB(theB)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Helper struct for testing move-only types
|
||||
struct SeqMoveOnlyType
|
||||
{
|
||||
int myValue;
|
||||
|
||||
explicit SeqMoveOnlyType(int theValue)
|
||||
: myValue(theValue)
|
||||
{
|
||||
}
|
||||
|
||||
SeqMoveOnlyType(SeqMoveOnlyType&& theOther) noexcept
|
||||
: myValue(theOther.myValue)
|
||||
{
|
||||
theOther.myValue = 0;
|
||||
}
|
||||
|
||||
SeqMoveOnlyType& operator=(SeqMoveOnlyType&& theOther) noexcept
|
||||
{
|
||||
myValue = theOther.myValue;
|
||||
theOther.myValue = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SeqMoveOnlyType(const SeqMoveOnlyType&) = delete;
|
||||
SeqMoveOnlyType& operator=(const SeqMoveOnlyType&) = delete;
|
||||
};
|
||||
|
||||
TEST(NCollection_SequenceTest, EmplaceAppend)
|
||||
{
|
||||
NCollection_Sequence<SeqMultiArgType> aSeq;
|
||||
|
||||
// Test EmplaceAppend with multiple constructor arguments
|
||||
SeqMultiArgType& aRef1 = aSeq.EmplaceAppend(42, 3.14);
|
||||
EXPECT_EQ(42, aRef1.myA);
|
||||
EXPECT_NEAR(3.14, aRef1.myB, 1e-10);
|
||||
EXPECT_EQ(1, aSeq.Size());
|
||||
|
||||
SeqMultiArgType& aRef2 = aSeq.EmplaceAppend(100, 2.71);
|
||||
EXPECT_EQ(100, aRef2.myA);
|
||||
EXPECT_NEAR(2.71, aRef2.myB, 1e-10);
|
||||
EXPECT_EQ(2, aSeq.Size());
|
||||
|
||||
// Verify the order (1-based indexing)
|
||||
EXPECT_EQ(42, aSeq(1).myA);
|
||||
EXPECT_EQ(100, aSeq(2).myA);
|
||||
}
|
||||
|
||||
TEST(NCollection_SequenceTest, EmplacePrepend)
|
||||
{
|
||||
NCollection_Sequence<SeqMultiArgType> aSeq;
|
||||
|
||||
// Test EmplacePrepend with multiple constructor arguments
|
||||
SeqMultiArgType& aRef1 = aSeq.EmplacePrepend(42, 3.14);
|
||||
EXPECT_EQ(42, aRef1.myA);
|
||||
EXPECT_NEAR(3.14, aRef1.myB, 1e-10);
|
||||
EXPECT_EQ(1, aSeq.Size());
|
||||
|
||||
SeqMultiArgType& aRef2 = aSeq.EmplacePrepend(100, 2.71);
|
||||
EXPECT_EQ(100, aRef2.myA);
|
||||
EXPECT_NEAR(2.71, aRef2.myB, 1e-10);
|
||||
EXPECT_EQ(2, aSeq.Size());
|
||||
|
||||
// Verify the order (prepended items should be at the front)
|
||||
EXPECT_EQ(100, aSeq.First().myA);
|
||||
EXPECT_EQ(42, aSeq.Last().myA);
|
||||
}
|
||||
|
||||
TEST(NCollection_SequenceTest, EmplaceAfterIterator)
|
||||
{
|
||||
NCollection_Sequence<SeqMultiArgType> aSeq;
|
||||
aSeq.EmplaceAppend(10, 1.0);
|
||||
aSeq.EmplaceAppend(30, 3.0);
|
||||
|
||||
// Get iterator to first element
|
||||
NCollection_Sequence<SeqMultiArgType>::Iterator anIter(aSeq);
|
||||
|
||||
// Emplace after the first element
|
||||
SeqMultiArgType& aRef = aSeq.EmplaceAfter(anIter, 20, 2.0);
|
||||
EXPECT_EQ(20, aRef.myA);
|
||||
EXPECT_NEAR(2.0, aRef.myB, 1e-10);
|
||||
|
||||
// Verify the order
|
||||
EXPECT_EQ(3, aSeq.Size());
|
||||
EXPECT_EQ(10, aSeq(1).myA);
|
||||
EXPECT_EQ(20, aSeq(2).myA);
|
||||
EXPECT_EQ(30, aSeq(3).myA);
|
||||
}
|
||||
|
||||
TEST(NCollection_SequenceTest, EmplaceAfterIndex)
|
||||
{
|
||||
NCollection_Sequence<SeqMultiArgType> aSeq;
|
||||
aSeq.EmplaceAppend(10, 1.0);
|
||||
aSeq.EmplaceAppend(30, 3.0);
|
||||
|
||||
// Emplace after index 1
|
||||
SeqMultiArgType& aRef = aSeq.EmplaceAfter(1, 20, 2.0);
|
||||
EXPECT_EQ(20, aRef.myA);
|
||||
EXPECT_NEAR(2.0, aRef.myB, 1e-10);
|
||||
|
||||
// Verify the order
|
||||
EXPECT_EQ(3, aSeq.Size());
|
||||
EXPECT_EQ(10, aSeq(1).myA);
|
||||
EXPECT_EQ(20, aSeq(2).myA);
|
||||
EXPECT_EQ(30, aSeq(3).myA);
|
||||
}
|
||||
|
||||
TEST(NCollection_SequenceTest, EmplaceBeforeIndex)
|
||||
{
|
||||
NCollection_Sequence<SeqMultiArgType> aSeq;
|
||||
aSeq.EmplaceAppend(10, 1.0);
|
||||
aSeq.EmplaceAppend(30, 3.0);
|
||||
|
||||
// Emplace before index 2
|
||||
SeqMultiArgType& aRef = aSeq.EmplaceBefore(2, 20, 2.0);
|
||||
EXPECT_EQ(20, aRef.myA);
|
||||
EXPECT_NEAR(2.0, aRef.myB, 1e-10);
|
||||
|
||||
// Verify the order
|
||||
EXPECT_EQ(3, aSeq.Size());
|
||||
EXPECT_EQ(10, aSeq(1).myA);
|
||||
EXPECT_EQ(20, aSeq(2).myA);
|
||||
EXPECT_EQ(30, aSeq(3).myA);
|
||||
}
|
||||
|
||||
TEST(NCollection_SequenceTest, EmplaceWithMoveOnlyType)
|
||||
{
|
||||
NCollection_Sequence<SeqMoveOnlyType> aSeq;
|
||||
|
||||
// Test EmplaceAppend with move-only type
|
||||
SeqMoveOnlyType& aRef1 = aSeq.EmplaceAppend(42);
|
||||
EXPECT_EQ(42, aRef1.myValue);
|
||||
|
||||
SeqMoveOnlyType& aRef2 = aSeq.EmplacePrepend(100);
|
||||
EXPECT_EQ(100, aRef2.myValue);
|
||||
|
||||
EXPECT_EQ(2, aSeq.Size());
|
||||
EXPECT_EQ(100, aSeq.First().myValue);
|
||||
EXPECT_EQ(42, aSeq.Last().myValue);
|
||||
}
|
||||
@@ -466,4 +466,182 @@ TEST(NCollection_VectorTest, STLAlgorithmCompatibility_Sort)
|
||||
std::sort(aStdVector.begin(), aStdVector.end());
|
||||
|
||||
EXPECT_TRUE(std::equal(aVector.begin(), aVector.end(), aStdVector.begin()));
|
||||
}
|
||||
|
||||
// Helper struct for testing in-place construction with multiple arguments
|
||||
struct VecMultiArgType
|
||||
{
|
||||
int myA;
|
||||
double myB;
|
||||
|
||||
VecMultiArgType()
|
||||
: myA(0),
|
||||
myB(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
VecMultiArgType(int theA, double theB)
|
||||
: myA(theA),
|
||||
myB(theB)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Helper struct for testing move-only types
|
||||
struct VecMoveOnlyType
|
||||
{
|
||||
int myValue;
|
||||
|
||||
VecMoveOnlyType()
|
||||
: myValue(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit VecMoveOnlyType(int theValue)
|
||||
: myValue(theValue)
|
||||
{
|
||||
}
|
||||
|
||||
VecMoveOnlyType(VecMoveOnlyType&& theOther) noexcept
|
||||
: myValue(theOther.myValue)
|
||||
{
|
||||
theOther.myValue = 0;
|
||||
}
|
||||
|
||||
VecMoveOnlyType& operator=(VecMoveOnlyType&& theOther) noexcept
|
||||
{
|
||||
myValue = theOther.myValue;
|
||||
theOther.myValue = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
VecMoveOnlyType(const VecMoveOnlyType&) = delete;
|
||||
VecMoveOnlyType& operator=(const VecMoveOnlyType&) = delete;
|
||||
};
|
||||
|
||||
TEST(NCollection_VectorTest, EmplaceAppend)
|
||||
{
|
||||
NCollection_Vector<VecMultiArgType> aVector;
|
||||
|
||||
// Test EmplaceAppend with multiple constructor arguments
|
||||
VecMultiArgType& aRef1 = aVector.EmplaceAppend(42, 3.14);
|
||||
EXPECT_EQ(42, aRef1.myA);
|
||||
EXPECT_NEAR(3.14, aRef1.myB, 1e-10);
|
||||
EXPECT_EQ(1, aVector.Length());
|
||||
|
||||
VecMultiArgType& aRef2 = aVector.EmplaceAppend(100, 2.71);
|
||||
EXPECT_EQ(100, aRef2.myA);
|
||||
EXPECT_NEAR(2.71, aRef2.myB, 1e-10);
|
||||
EXPECT_EQ(2, aVector.Length());
|
||||
|
||||
// Verify the order (0-based indexing)
|
||||
EXPECT_EQ(42, aVector(0).myA);
|
||||
EXPECT_EQ(100, aVector(1).myA);
|
||||
}
|
||||
|
||||
TEST(NCollection_VectorTest, EmplaceValue)
|
||||
{
|
||||
NCollection_Vector<VecMultiArgType> aVector;
|
||||
|
||||
// Test EmplaceValue at index 0
|
||||
VecMultiArgType& aRef1 = aVector.EmplaceValue(0, 10, 1.0);
|
||||
EXPECT_EQ(10, aRef1.myA);
|
||||
EXPECT_NEAR(1.0, aRef1.myB, 1e-10);
|
||||
EXPECT_EQ(1, aVector.Length());
|
||||
|
||||
// Test EmplaceValue at index beyond current size (should fill with default values)
|
||||
VecMultiArgType& aRef2 = aVector.EmplaceValue(3, 40, 4.0);
|
||||
EXPECT_EQ(40, aRef2.myA);
|
||||
EXPECT_NEAR(4.0, aRef2.myB, 1e-10);
|
||||
EXPECT_EQ(4, aVector.Length());
|
||||
|
||||
// Check that intermediate elements were default-constructed
|
||||
EXPECT_EQ(0, aVector(1).myA);
|
||||
EXPECT_NEAR(0.0, aVector(1).myB, 1e-10);
|
||||
EXPECT_EQ(0, aVector(2).myA);
|
||||
EXPECT_NEAR(0.0, aVector(2).myB, 1e-10);
|
||||
}
|
||||
|
||||
TEST(NCollection_VectorTest, EmplaceValue_ReplacesExisting)
|
||||
{
|
||||
NCollection_Vector<VecMultiArgType> aVector;
|
||||
|
||||
// Set initial values
|
||||
aVector.EmplaceValue(0, 10, 1.0);
|
||||
aVector.EmplaceValue(1, 20, 2.0);
|
||||
aVector.EmplaceValue(2, 30, 3.0);
|
||||
|
||||
EXPECT_EQ(3, aVector.Length());
|
||||
|
||||
// Replace value at index 1 (existing element)
|
||||
VecMultiArgType& aRef = aVector.EmplaceValue(1, 200, 20.0);
|
||||
EXPECT_EQ(200, aRef.myA);
|
||||
EXPECT_NEAR(20.0, aRef.myB, 1e-10);
|
||||
|
||||
// Verify other values unchanged and size unchanged
|
||||
EXPECT_EQ(3, aVector.Length());
|
||||
EXPECT_EQ(10, aVector(0).myA);
|
||||
EXPECT_EQ(200, aVector(1).myA);
|
||||
EXPECT_EQ(30, aVector(2).myA);
|
||||
}
|
||||
|
||||
TEST(NCollection_VectorTest, EmplaceWithMoveOnlyType)
|
||||
{
|
||||
NCollection_Vector<VecMoveOnlyType> aVector;
|
||||
|
||||
// Test EmplaceAppend with move-only type
|
||||
VecMoveOnlyType& aRef1 = aVector.EmplaceAppend(42);
|
||||
EXPECT_EQ(42, aRef1.myValue);
|
||||
|
||||
VecMoveOnlyType& aRef2 = aVector.EmplaceAppend(100);
|
||||
EXPECT_EQ(100, aRef2.myValue);
|
||||
|
||||
EXPECT_EQ(2, aVector.Length());
|
||||
EXPECT_EQ(42, aVector(0).myValue);
|
||||
EXPECT_EQ(100, aVector(1).myValue);
|
||||
}
|
||||
|
||||
TEST(NCollection_VectorTest, EmplaceAppendMany)
|
||||
{
|
||||
NCollection_Vector<VecMultiArgType> aVector;
|
||||
|
||||
// Test EmplaceAppend with many elements to trigger internal array expansion
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
VecMultiArgType& aRef = aVector.EmplaceAppend(i, static_cast<double>(i) * 0.1);
|
||||
EXPECT_EQ(i, aRef.myA);
|
||||
EXPECT_NEAR(static_cast<double>(i) * 0.1, aRef.myB, 1e-10);
|
||||
}
|
||||
|
||||
EXPECT_EQ(1000, aVector.Length());
|
||||
|
||||
// Verify all values
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
EXPECT_EQ(i, aVector(i).myA);
|
||||
EXPECT_NEAR(static_cast<double>(i) * 0.1, aVector(i).myB, 1e-10);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NCollection_VectorTest, SetValue_ReplacesExisting)
|
||||
{
|
||||
NCollection_Vector<VecMultiArgType> aVector;
|
||||
|
||||
// Set initial values
|
||||
aVector.SetValue(0, VecMultiArgType(10, 1.0));
|
||||
aVector.SetValue(1, VecMultiArgType(20, 2.0));
|
||||
aVector.SetValue(2, VecMultiArgType(30, 3.0));
|
||||
|
||||
EXPECT_EQ(3, aVector.Length());
|
||||
|
||||
// Replace value at index 1 (existing element)
|
||||
VecMultiArgType& aRef = aVector.SetValue(1, VecMultiArgType(200, 20.0));
|
||||
EXPECT_EQ(200, aRef.myA);
|
||||
EXPECT_NEAR(20.0, aRef.myB, 1e-10);
|
||||
|
||||
// Verify other values unchanged and size unchanged
|
||||
EXPECT_EQ(3, aVector.Length());
|
||||
EXPECT_EQ(10, aVector(0).myA);
|
||||
EXPECT_EQ(200, aVector(1).myA);
|
||||
EXPECT_EQ(30, aVector(2).myA);
|
||||
}
|
||||
@@ -325,6 +325,21 @@ public:
|
||||
myPointer[aPos] = std::forward<value_type>(theItem);
|
||||
}
|
||||
|
||||
//! Emplace value at the specified index, constructing it in-place
|
||||
//! @param theIndex index at which to emplace the value
|
||||
//! @param theArgs arguments forwarded to TheItemType constructor
|
||||
//! @return reference to the newly constructed item
|
||||
template <typename... Args>
|
||||
reference EmplaceValue(const int theIndex, Args&&... theArgs)
|
||||
{
|
||||
const size_t aPos = theIndex - myLowerBound;
|
||||
Standard_OutOfRange_Raise_if(aPos >= mySize, "NCollection_Array1::EmplaceValue");
|
||||
pointer aPnt = myPointer + aPos;
|
||||
myAllocator.destroy(aPnt);
|
||||
myAllocator.construct(aPnt, std::forward<Args>(theArgs)...);
|
||||
return *aPnt;
|
||||
}
|
||||
|
||||
//! Changes the lowest bound. Do not move data
|
||||
void UpdateLowerBound(const int theLower) noexcept { myLowerBound = theLower; }
|
||||
|
||||
|
||||
@@ -305,6 +305,22 @@ public:
|
||||
NCollection_Array1<TheItemType>::at(aPos) = std::forward<TheItemType>(theItem);
|
||||
}
|
||||
|
||||
//! Emplace value at the specified row and column, constructing it in-place
|
||||
//! @param theRow row index at which to emplace the value
|
||||
//! @param theCol column index at which to emplace the value
|
||||
//! @param theArgs arguments forwarded to TheItemType constructor
|
||||
//! @return reference to the newly constructed item
|
||||
template <typename... Args>
|
||||
reference EmplaceValue(const int theRow, const int theCol, Args&&... theArgs)
|
||||
{
|
||||
const size_t aPos = (theRow - myLowerRow) * mySizeCol + (theCol - myLowerCol);
|
||||
Standard_OutOfRange_Raise_if(aPos >= this->mySize, "NCollection_Array2::EmplaceValue");
|
||||
pointer aPnt = this->myPointer + aPos;
|
||||
this->myAllocator.destroy(aPnt);
|
||||
this->myAllocator.construct(aPnt, std::forward<Args>(theArgs)...);
|
||||
return *aPnt;
|
||||
}
|
||||
|
||||
//! 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.
|
||||
|
||||
@@ -257,6 +257,54 @@ public: //! @name public methods
|
||||
return *aPnt;
|
||||
}
|
||||
|
||||
//! Emplace one item at the end, constructing it in-place
|
||||
//! @param theArgs arguments forwarded to TheItemType constructor
|
||||
//! @return reference to the newly constructed item
|
||||
template <typename... Args>
|
||||
reference EmplaceAppend(Args&&... theArgs)
|
||||
{
|
||||
if (myUsedSize >= availableSize())
|
||||
{
|
||||
expandArray();
|
||||
}
|
||||
pointer aPnt = &at(myUsedSize++);
|
||||
myAlloc.construct(aPnt, std::forward<Args>(theArgs)...);
|
||||
return *aPnt;
|
||||
}
|
||||
|
||||
//! Emplace value at the specified index, constructing it in-place
|
||||
//! If the index is beyond current size, default-constructs intermediate elements
|
||||
//! @param theIndex index at which to emplace the value
|
||||
//! @param theArgs arguments forwarded to TheItemType constructor
|
||||
//! @return reference to the newly constructed item
|
||||
template <typename... Args>
|
||||
reference EmplaceValue(const int theIndex, Args&&... theArgs)
|
||||
{
|
||||
const size_t aBlockInd = static_cast<size_t>(theIndex / myInternalSize);
|
||||
const size_t anIndex = static_cast<size_t>(theIndex);
|
||||
for (size_t aInd = myContainer.Size(); aInd <= aBlockInd; aInd++)
|
||||
{
|
||||
expandArray();
|
||||
}
|
||||
const bool isExisting = anIndex < myUsedSize;
|
||||
if (!isExisting)
|
||||
{
|
||||
for (; myUsedSize < anIndex; myUsedSize++)
|
||||
{
|
||||
pointer aPnt = &at(myUsedSize);
|
||||
myAlloc.construct(aPnt);
|
||||
}
|
||||
myUsedSize++;
|
||||
}
|
||||
pointer aPnt = &at(anIndex);
|
||||
if (isExisting)
|
||||
{
|
||||
myAlloc.destroy(aPnt);
|
||||
}
|
||||
myAlloc.construct(aPnt, std::forward<Args>(theArgs)...);
|
||||
return *aPnt;
|
||||
}
|
||||
|
||||
//! Operator() - query the const value
|
||||
const_reference operator()(const int theIndex) const noexcept { return Value(theIndex); }
|
||||
|
||||
@@ -303,7 +351,8 @@ public: //! @name public methods
|
||||
{
|
||||
expandArray();
|
||||
}
|
||||
if (myUsedSize <= anIndex)
|
||||
const bool isExisting = anIndex < myUsedSize;
|
||||
if (!isExisting)
|
||||
{
|
||||
for (; myUsedSize < anIndex; myUsedSize++)
|
||||
{
|
||||
@@ -313,6 +362,10 @@ public: //! @name public methods
|
||||
myUsedSize++;
|
||||
}
|
||||
pointer aPnt = &at(anIndex);
|
||||
if (isExisting)
|
||||
{
|
||||
myAlloc.destroy(aPnt);
|
||||
}
|
||||
myAlloc.construct(aPnt, theValue);
|
||||
return *aPnt;
|
||||
}
|
||||
@@ -326,7 +379,8 @@ public: //! @name public methods
|
||||
{
|
||||
expandArray();
|
||||
}
|
||||
if (myUsedSize <= anIndex)
|
||||
const bool isExisting = anIndex < myUsedSize;
|
||||
if (!isExisting)
|
||||
{
|
||||
for (; myUsedSize < anIndex; myUsedSize++)
|
||||
{
|
||||
@@ -336,6 +390,10 @@ public: //! @name public methods
|
||||
myUsedSize++;
|
||||
}
|
||||
pointer aPnt = &at(anIndex);
|
||||
if (isExisting)
|
||||
{
|
||||
myAlloc.destroy(aPnt);
|
||||
}
|
||||
myAlloc.construct(aPnt, std::forward<TheItemType>(theValue));
|
||||
return *aPnt;
|
||||
}
|
||||
|
||||
@@ -343,6 +343,56 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
//! Emplace one item at the end, constructing it in-place
|
||||
//! @param theArgs arguments forwarded to TheItemType constructor
|
||||
//! @return reference to the newly constructed item
|
||||
template <typename... Args>
|
||||
TheItemType& EmplaceAppend(Args&&... theArgs)
|
||||
{
|
||||
ListNode* pNew =
|
||||
new (this->myAllocator) ListNode(std::in_place, nullptr, std::forward<Args>(theArgs)...);
|
||||
PAppend(pNew);
|
||||
return ((ListNode*)PLast())->ChangeValue();
|
||||
}
|
||||
|
||||
//! Emplace one item at the beginning, constructing it in-place
|
||||
//! @param theArgs arguments forwarded to TheItemType constructor
|
||||
//! @return reference to the newly constructed item
|
||||
template <typename... Args>
|
||||
TheItemType& EmplacePrepend(Args&&... theArgs)
|
||||
{
|
||||
ListNode* pNew =
|
||||
new (this->myAllocator) ListNode(std::in_place, nullptr, std::forward<Args>(theArgs)...);
|
||||
PPrepend(pNew);
|
||||
return ((ListNode*)PFirst())->ChangeValue();
|
||||
}
|
||||
|
||||
//! Emplace one item before the iterator position, constructing it in-place
|
||||
//! @param theIter iterator pointing to the position before which to insert
|
||||
//! @param theArgs arguments forwarded to TheItemType constructor
|
||||
//! @return reference to the newly constructed item
|
||||
template <typename... Args>
|
||||
TheItemType& EmplaceBefore(Iterator& theIter, Args&&... theArgs)
|
||||
{
|
||||
ListNode* pNew =
|
||||
new (this->myAllocator) ListNode(std::in_place, nullptr, std::forward<Args>(theArgs)...);
|
||||
PInsertBefore(pNew, theIter);
|
||||
return pNew->ChangeValue();
|
||||
}
|
||||
|
||||
//! Emplace one item after the iterator position, constructing it in-place
|
||||
//! @param theIter iterator pointing to the position after which to insert
|
||||
//! @param theArgs arguments forwarded to TheItemType constructor
|
||||
//! @return reference to the newly constructed item
|
||||
template <typename... Args>
|
||||
TheItemType& EmplaceAfter(Iterator& theIter, Args&&... theArgs)
|
||||
{
|
||||
ListNode* pNew =
|
||||
new (this->myAllocator) ListNode(std::in_place, nullptr, std::forward<Args>(theArgs)...);
|
||||
PInsertAfter(pNew, theIter);
|
||||
return pNew->ChangeValue();
|
||||
}
|
||||
|
||||
//! Reverse the list
|
||||
void Reverse() { PReverse(); }
|
||||
|
||||
|
||||
@@ -53,6 +53,14 @@ public:
|
||||
myValue = std::forward<TheItemType>(theItem);
|
||||
}
|
||||
|
||||
//! Constructor with in-place value construction
|
||||
template <typename... Args>
|
||||
Node(std::in_place_t, Args&&... theArgs)
|
||||
: NCollection_SeqNode(),
|
||||
myValue(std::forward<Args>(theArgs)...)
|
||||
{
|
||||
}
|
||||
|
||||
//! Constant value access
|
||||
const TheItemType& Value() const noexcept { return myValue; }
|
||||
|
||||
@@ -370,6 +378,64 @@ public:
|
||||
PInsertAfter(theIndex, new (this->myAllocator) Node(theItem));
|
||||
}
|
||||
|
||||
//! Emplace one item at the end, constructing it in-place
|
||||
//! @param theArgs arguments forwarded to TheItemType constructor
|
||||
//! @return reference to the newly constructed item
|
||||
template <typename... Args>
|
||||
TheItemType& EmplaceAppend(Args&&... theArgs)
|
||||
{
|
||||
Node* pNew = new (this->myAllocator) Node(std::in_place, std::forward<Args>(theArgs)...);
|
||||
PAppend(pNew);
|
||||
return ((Node*)myLastItem)->ChangeValue();
|
||||
}
|
||||
|
||||
//! Emplace one item at the beginning, constructing it in-place
|
||||
//! @param theArgs arguments forwarded to TheItemType constructor
|
||||
//! @return reference to the newly constructed item
|
||||
template <typename... Args>
|
||||
TheItemType& EmplacePrepend(Args&&... theArgs)
|
||||
{
|
||||
Node* pNew = new (this->myAllocator) Node(std::in_place, std::forward<Args>(theArgs)...);
|
||||
PPrepend(pNew);
|
||||
return ((Node*)myFirstItem)->ChangeValue();
|
||||
}
|
||||
|
||||
//! Emplace one item after the position of iterator, constructing it in-place
|
||||
//! @param thePosition iterator pointing to the position after which to insert
|
||||
//! @param theArgs arguments forwarded to TheItemType constructor
|
||||
//! @return reference to the newly constructed item
|
||||
template <typename... Args>
|
||||
TheItemType& EmplaceAfter(Iterator& thePosition, Args&&... theArgs)
|
||||
{
|
||||
Node* pNew = new (this->myAllocator) Node(std::in_place, std::forward<Args>(theArgs)...);
|
||||
PInsertAfter(thePosition, pNew);
|
||||
return pNew->ChangeValue();
|
||||
}
|
||||
|
||||
//! Emplace one item after the specified index, constructing it in-place
|
||||
//! @param theIndex index after which to insert (0 means insert at beginning)
|
||||
//! @param theArgs arguments forwarded to TheItemType constructor
|
||||
//! @return reference to the newly constructed item
|
||||
template <typename... Args>
|
||||
TheItemType& EmplaceAfter(const int theIndex, Args&&... theArgs)
|
||||
{
|
||||
Standard_OutOfRange_Raise_if(theIndex < 0 || theIndex > mySize,
|
||||
"NCollection_Sequence::EmplaceAfter");
|
||||
Node* pNew = new (this->myAllocator) Node(std::in_place, std::forward<Args>(theArgs)...);
|
||||
PInsertAfter(theIndex, pNew);
|
||||
return pNew->ChangeValue();
|
||||
}
|
||||
|
||||
//! Emplace one item before the specified index, constructing it in-place
|
||||
//! @param theIndex index before which to insert
|
||||
//! @param theArgs arguments forwarded to TheItemType constructor
|
||||
//! @return reference to the newly constructed item
|
||||
template <typename... Args>
|
||||
TheItemType& EmplaceBefore(const int theIndex, Args&&... theArgs)
|
||||
{
|
||||
return EmplaceAfter(theIndex - 1, std::forward<Args>(theArgs)...);
|
||||
}
|
||||
|
||||
//! Split in two sequences
|
||||
void Split(const int theIndex, NCollection_Sequence& theSeq)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user