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:
Pasukhin Dmitry
2026-01-28 16:42:43 +00:00
committed by GitHub
parent 8a31910e06
commit 218862282b
10 changed files with 808 additions and 2 deletions

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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; }

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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(); }

View File

@@ -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)
{