mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-09-07 05:08:13 +08:00
Foundation - Array adding option to work with size_t (#1236)
- Added zero-based constructors (allocation + buffer-reuse wrapping) to `NCollection_Array1` and `NCollection_Array2`. - Added `size_t`-based `Resize()` overloads (and refactored `NCollection_Array1` resize logic into a shared implementation). - Added GTest coverage for the new zero-based construction / access / resize behaviors.
This commit is contained in:
@@ -475,3 +475,175 @@ TEST(NCollection_Array1Test, EmplaceValue_ReplacesExisting)
|
||||
EXPECT_EQ(200, anArray(2).myA);
|
||||
EXPECT_EQ(30, anArray(3).myA);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Zero-based (size_t) construction mode tests
|
||||
// ============================================================================
|
||||
|
||||
TEST(NCollection_Array1Test, SizeConstructor_AllocatesCorrectly)
|
||||
{
|
||||
const size_t aSize = 10;
|
||||
NCollection_Array1<int> anArray(aSize);
|
||||
|
||||
EXPECT_EQ(aSize, anArray.Size());
|
||||
EXPECT_EQ(0, anArray.Lower());
|
||||
EXPECT_EQ(static_cast<int>(aSize) - 1, anArray.Upper());
|
||||
EXPECT_FALSE(anArray.IsEmpty());
|
||||
EXPECT_TRUE(anArray.IsDeletable());
|
||||
}
|
||||
|
||||
TEST(NCollection_Array1Test, SizeConstructor_ZeroSize)
|
||||
{
|
||||
NCollection_Array1<int> anArray(static_cast<size_t>(0));
|
||||
|
||||
EXPECT_EQ(0u, anArray.Size());
|
||||
EXPECT_TRUE(anArray.IsEmpty());
|
||||
}
|
||||
|
||||
TEST(NCollection_Array1Test, SizeConstructor_AtAccess)
|
||||
{
|
||||
const size_t aSize = 5;
|
||||
NCollection_Array1<int> anArray(aSize);
|
||||
|
||||
for (size_t i = 0; i < aSize; ++i)
|
||||
{
|
||||
anArray.ChangeAt(i) = static_cast<int>(i * 10);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < aSize; ++i)
|
||||
{
|
||||
EXPECT_EQ(static_cast<int>(i * 10), anArray.At(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NCollection_Array1Test, SizeConstructor_IteratorAccess)
|
||||
{
|
||||
const size_t aSize = 6;
|
||||
NCollection_Array1<int> anArray(aSize);
|
||||
|
||||
int aFill = 0;
|
||||
for (auto& aVal : anArray)
|
||||
{
|
||||
aVal = aFill++;
|
||||
}
|
||||
|
||||
int aCheck = 0;
|
||||
for (const auto& aVal : anArray)
|
||||
{
|
||||
EXPECT_EQ(aCheck++, aVal);
|
||||
}
|
||||
EXPECT_EQ(static_cast<int>(aSize), aCheck);
|
||||
}
|
||||
|
||||
TEST(NCollection_Array1Test, SizeConstructor_LegacyValueOperator)
|
||||
{
|
||||
// When lower==0, operator[](i) should also work 0-based
|
||||
const size_t aSize = 4;
|
||||
NCollection_Array1<int> anArray(aSize);
|
||||
for (size_t i = 0; i < aSize; ++i)
|
||||
{
|
||||
anArray[static_cast<int>(i)] = static_cast<int>(i + 100);
|
||||
}
|
||||
for (size_t i = 0; i < aSize; ++i)
|
||||
{
|
||||
EXPECT_EQ(static_cast<int>(i + 100), anArray[static_cast<int>(i)]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NCollection_Array1Test, SizeConstructor_BufferReuse_NotOwner)
|
||||
{
|
||||
int aBuf[8] = {10, 20, 30, 40, 50, 60, 70, 80};
|
||||
NCollection_Array1<int> anArray(aBuf, 8);
|
||||
|
||||
EXPECT_FALSE(anArray.IsDeletable());
|
||||
EXPECT_EQ(8u, anArray.Size());
|
||||
EXPECT_EQ(0, anArray.Lower());
|
||||
EXPECT_EQ(7, anArray.Upper());
|
||||
}
|
||||
|
||||
TEST(NCollection_Array1Test, SizeConstructor_BufferReuse_DataPreserved)
|
||||
{
|
||||
int aBuf[5] = {1, 2, 3, 4, 5};
|
||||
NCollection_Array1<int> anArray(aBuf, 5);
|
||||
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
{
|
||||
EXPECT_EQ(static_cast<int>(i + 1), anArray.At(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NCollection_Array1Test, SizeConstructor_BufferReuse_WritesGoToBuffer)
|
||||
{
|
||||
int aBuf[4] = {0, 0, 0, 0};
|
||||
{
|
||||
NCollection_Array1<int> anArray(aBuf, 4);
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
{
|
||||
anArray.ChangeAt(i) = static_cast<int>(i + 7);
|
||||
}
|
||||
}
|
||||
// After array goes out of scope, buffer should still hold written values
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
EXPECT_EQ(i + 7, aBuf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NCollection_Array1Test, SizeConstructor_Resize_Grow)
|
||||
{
|
||||
NCollection_Array1<int> anArray(static_cast<size_t>(3));
|
||||
anArray.ChangeAt(0) = 10;
|
||||
anArray.ChangeAt(1) = 20;
|
||||
anArray.ChangeAt(2) = 30;
|
||||
|
||||
anArray.Resize(static_cast<size_t>(5), true);
|
||||
|
||||
EXPECT_EQ(5u, anArray.Size());
|
||||
EXPECT_EQ(10, anArray.At(0));
|
||||
EXPECT_EQ(20, anArray.At(1));
|
||||
EXPECT_EQ(30, anArray.At(2));
|
||||
}
|
||||
|
||||
TEST(NCollection_Array1Test, SizeConstructor_Resize_Shrink)
|
||||
{
|
||||
NCollection_Array1<int> anArray(static_cast<size_t>(5));
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
{
|
||||
anArray.ChangeAt(i) = static_cast<int>(i);
|
||||
}
|
||||
|
||||
anArray.Resize(static_cast<size_t>(3), true);
|
||||
|
||||
EXPECT_EQ(3u, anArray.Size());
|
||||
EXPECT_EQ(0, anArray.At(0));
|
||||
EXPECT_EQ(1, anArray.At(1));
|
||||
EXPECT_EQ(2, anArray.At(2));
|
||||
}
|
||||
|
||||
TEST(NCollection_Array1Test, SizeConstructor_Resize_NoData)
|
||||
{
|
||||
NCollection_Array1<int> anArray(static_cast<size_t>(4));
|
||||
anArray.ChangeAt(0) = 99;
|
||||
|
||||
anArray.Resize(static_cast<size_t>(6), false);
|
||||
|
||||
EXPECT_EQ(6u, anArray.Size());
|
||||
EXPECT_TRUE(anArray.IsDeletable());
|
||||
}
|
||||
|
||||
TEST(NCollection_Array1Test, SizeConstructor_MoveSemantics)
|
||||
{
|
||||
NCollection_Array1<int> anSrc(static_cast<size_t>(3));
|
||||
anSrc.ChangeAt(0) = 1;
|
||||
anSrc.ChangeAt(1) = 2;
|
||||
anSrc.ChangeAt(2) = 3;
|
||||
|
||||
NCollection_Array1<int> anDst(std::move(anSrc));
|
||||
|
||||
EXPECT_EQ(3u, anDst.Size());
|
||||
EXPECT_EQ(1, anDst.At(0));
|
||||
EXPECT_EQ(2, anDst.At(1));
|
||||
EXPECT_EQ(3, anDst.At(2));
|
||||
EXPECT_EQ(0u, anSrc.Size());
|
||||
EXPECT_TRUE(anSrc.IsEmpty());
|
||||
}
|
||||
|
||||
@@ -629,4 +629,133 @@ TEST(NCollection_Array2Test, ResizeWithTrim_GrowPreservesOldRegion)
|
||||
EXPECT_EQ(99, anArray(aRow, aCol));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Zero-based (size_t) construction mode tests
|
||||
// ============================================================================
|
||||
|
||||
TEST(NCollection_Array2Test, SizeConstructor_AllocatesCorrectly)
|
||||
{
|
||||
const size_t aNbRows = 3;
|
||||
const size_t aNbCols = 4;
|
||||
NCollection_Array2<int> anArray(aNbRows, aNbCols);
|
||||
|
||||
EXPECT_EQ(aNbRows, static_cast<size_t>(anArray.NbRows()));
|
||||
EXPECT_EQ(aNbCols, static_cast<size_t>(anArray.NbColumns()));
|
||||
EXPECT_EQ(aNbRows * aNbCols, anArray.Size());
|
||||
EXPECT_EQ(0, anArray.LowerRow());
|
||||
EXPECT_EQ(0, anArray.LowerCol());
|
||||
EXPECT_EQ(static_cast<int>(aNbRows) - 1, anArray.UpperRow());
|
||||
EXPECT_EQ(static_cast<int>(aNbCols) - 1, anArray.UpperCol());
|
||||
EXPECT_TRUE(anArray.IsDeletable());
|
||||
}
|
||||
|
||||
TEST(NCollection_Array2Test, SizeConstructor_AtAccess)
|
||||
{
|
||||
const size_t aNbRows = 3;
|
||||
const size_t aNbCols = 5;
|
||||
NCollection_Array2<int> anArray(aNbRows, aNbCols);
|
||||
|
||||
for (size_t aRow = 0; aRow < aNbRows; ++aRow)
|
||||
{
|
||||
for (size_t aCol = 0; aCol < aNbCols; ++aCol)
|
||||
{
|
||||
anArray.ChangeAt(aRow, aCol) = static_cast<int>(aRow * 100 + aCol);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t aRow = 0; aRow < aNbRows; ++aRow)
|
||||
{
|
||||
for (size_t aCol = 0; aCol < aNbCols; ++aCol)
|
||||
{
|
||||
EXPECT_EQ(static_cast<int>(aRow * 100 + aCol), anArray.At(aRow, aCol));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NCollection_Array2Test, SizeConstructor_LegacyOperatorZeroBased)
|
||||
{
|
||||
// When LowerRow/Col == 0, operator()(row, col) is also 0-based
|
||||
NCollection_Array2<int> anArray(static_cast<size_t>(2), static_cast<size_t>(3));
|
||||
anArray(0, 0) = 1;
|
||||
anArray(0, 1) = 2;
|
||||
anArray(1, 2) = 9;
|
||||
|
||||
EXPECT_EQ(1, anArray.At(0, 0));
|
||||
EXPECT_EQ(2, anArray.At(0, 1));
|
||||
EXPECT_EQ(9, anArray.At(1, 2));
|
||||
}
|
||||
|
||||
TEST(NCollection_Array2Test, SizeConstructor_BufferReuse_NotOwner)
|
||||
{
|
||||
int aBuf[6] = {1, 2, 3, 4, 5, 6};
|
||||
NCollection_Array2<int> anArray(aBuf, 2, 3);
|
||||
|
||||
EXPECT_FALSE(anArray.IsDeletable());
|
||||
EXPECT_EQ(2, anArray.NbRows());
|
||||
EXPECT_EQ(3, anArray.NbColumns());
|
||||
EXPECT_EQ(0, anArray.LowerRow());
|
||||
EXPECT_EQ(0, anArray.LowerCol());
|
||||
}
|
||||
|
||||
TEST(NCollection_Array2Test, SizeConstructor_BufferReuse_DataPreserved)
|
||||
{
|
||||
// Row-major layout: buf[row * nbCols + col]
|
||||
int aBuf[6] = {10, 20, 30, 40, 50, 60};
|
||||
NCollection_Array2<int> anArray(aBuf, 2, 3);
|
||||
|
||||
EXPECT_EQ(10, anArray.At(0, 0));
|
||||
EXPECT_EQ(20, anArray.At(0, 1));
|
||||
EXPECT_EQ(30, anArray.At(0, 2));
|
||||
EXPECT_EQ(40, anArray.At(1, 0));
|
||||
EXPECT_EQ(50, anArray.At(1, 1));
|
||||
EXPECT_EQ(60, anArray.At(1, 2));
|
||||
}
|
||||
|
||||
TEST(NCollection_Array2Test, SizeConstructor_Resize_Grow)
|
||||
{
|
||||
NCollection_Array2<int> anArray(static_cast<size_t>(2), static_cast<size_t>(2));
|
||||
anArray.Init(7);
|
||||
|
||||
anArray.Resize(static_cast<size_t>(3), static_cast<size_t>(3), true);
|
||||
|
||||
EXPECT_EQ(3, anArray.NbRows());
|
||||
EXPECT_EQ(3, anArray.NbColumns());
|
||||
// Original 2x2 values (linear copy) should be preserved in first 4 elements
|
||||
EXPECT_EQ(7, anArray.At(0, 0));
|
||||
EXPECT_EQ(7, anArray.At(0, 1));
|
||||
}
|
||||
|
||||
TEST(NCollection_Array2Test, SizeConstructor_Resize_NoData)
|
||||
{
|
||||
NCollection_Array2<int> anArray(static_cast<size_t>(3), static_cast<size_t>(4));
|
||||
anArray.Init(5);
|
||||
|
||||
anArray.Resize(static_cast<size_t>(2), static_cast<size_t>(2), false);
|
||||
|
||||
EXPECT_EQ(2, anArray.NbRows());
|
||||
EXPECT_EQ(2, anArray.NbColumns());
|
||||
EXPECT_EQ(0, anArray.LowerRow());
|
||||
EXPECT_EQ(0, anArray.LowerCol());
|
||||
EXPECT_TRUE(anArray.IsDeletable());
|
||||
}
|
||||
|
||||
TEST(NCollection_Array2Test, SizeConstructor_ResizeWithTrim_GrowPreserves)
|
||||
{
|
||||
NCollection_Array2<int> anArray(static_cast<size_t>(2), static_cast<size_t>(2));
|
||||
anArray.Init(42);
|
||||
|
||||
anArray.ResizeWithTrim(static_cast<size_t>(3), static_cast<size_t>(3), true);
|
||||
|
||||
EXPECT_EQ(3, anArray.NbRows());
|
||||
EXPECT_EQ(3, anArray.NbColumns());
|
||||
// Original 2x2 corner should be preserved
|
||||
for (size_t aRow = 0; aRow < 2; ++aRow)
|
||||
{
|
||||
for (size_t aCol = 0; aCol < 2; ++aCol)
|
||||
{
|
||||
EXPECT_EQ(42, anArray.At(aRow, aCol));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,19 @@
|
||||
//! @code
|
||||
//! for (i = A.Lower(); i <= A.Upper(); i++)
|
||||
//! @endcode
|
||||
//!
|
||||
//! Zero-based (size_t) construction mode:
|
||||
//! Use NCollection_Array1(size_t theSize) or NCollection_Array1(pointer, size_t) to create
|
||||
//! a zero-based array (Lower()==0). In this mode At()/ChangeAt() and STL iterators are the
|
||||
//! preferred access path - they address elements directly without any offset subtraction.
|
||||
//! Buffer-reuse variants do NOT own the memory and will not free it on destruction.
|
||||
//! @code
|
||||
//! int aBuffer[100];
|
||||
//! NCollection_Array1<int> aZero(100); // allocates, lower=0
|
||||
//! NCollection_Array1<int> aWrap(aBuffer, 100); // wraps aBuffer, lower=0, not owner
|
||||
//! for (size_t i = 0; i < aWrap.Size(); ++i)
|
||||
//! aWrap.At(i) = static_cast<int>(i);
|
||||
//! @endcode
|
||||
template <class TheItemType>
|
||||
class NCollection_Array1
|
||||
{
|
||||
@@ -114,24 +127,6 @@ public:
|
||||
construct(0, mySize);
|
||||
}
|
||||
|
||||
explicit NCollection_Array1(const allocator_type& theAlloc,
|
||||
const int theLower,
|
||||
const int theUpper)
|
||||
: myLowerBound(theLower),
|
||||
mySize(theUpper - theLower + 1),
|
||||
myPointer(nullptr),
|
||||
myIsOwner(false),
|
||||
myAllocator(theAlloc)
|
||||
{
|
||||
if (mySize == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
myPointer = myAllocator.allocate(mySize);
|
||||
myIsOwner = true;
|
||||
construct(0, mySize);
|
||||
}
|
||||
|
||||
explicit NCollection_Array1(const_reference theBegin,
|
||||
const int theLower,
|
||||
const int theUpper,
|
||||
@@ -150,6 +145,32 @@ public:
|
||||
construct(0, mySize);
|
||||
}
|
||||
|
||||
//! Zero-based constructor: allocates theSize elements with lower bound 0.
|
||||
//! Use At()/ChangeAt() or STL iterators for optimal access (no offset subtraction).
|
||||
explicit NCollection_Array1(const size_t theSize)
|
||||
: myLowerBound(0),
|
||||
mySize(theSize)
|
||||
{
|
||||
if (mySize == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
myPointer = myAllocator.allocate(mySize);
|
||||
myIsOwner = true;
|
||||
construct(0, mySize);
|
||||
}
|
||||
|
||||
//! Zero-based buffer-reuse constructor: wraps an existing C array of theSize elements.
|
||||
//! The array does NOT own the buffer and will NOT free it on destruction.
|
||||
//! Use At()/ChangeAt() or STL iterators for optimal access (no offset subtraction).
|
||||
explicit NCollection_Array1(pointer theBegin, const size_t theSize)
|
||||
: myLowerBound(0),
|
||||
mySize(theSize),
|
||||
myPointer(theBegin),
|
||||
myIsOwner(false)
|
||||
{
|
||||
}
|
||||
|
||||
//! Copy constructor
|
||||
NCollection_Array1(const NCollection_Array1& theOther)
|
||||
: myLowerBound(theOther.myLowerBound),
|
||||
@@ -364,44 +385,15 @@ public:
|
||||
void Resize(const int theLower, const int theUpper, const bool theToCopyData)
|
||||
{
|
||||
Standard_RangeError_Raise_if(theUpper < theLower, "NCollection_Array1::Resize");
|
||||
const size_t aNewSize = static_cast<size_t>(theUpper - theLower + 1);
|
||||
pointer aPrevContPnt = myPointer;
|
||||
if (aNewSize == mySize)
|
||||
{
|
||||
myLowerBound = theLower;
|
||||
return;
|
||||
}
|
||||
if (myIsOwner)
|
||||
{
|
||||
if (theToCopyData)
|
||||
destroy(myPointer, aNewSize, mySize);
|
||||
else
|
||||
destroy(myPointer, 0, mySize);
|
||||
}
|
||||
myLowerBound = theLower;
|
||||
if (theToCopyData)
|
||||
{
|
||||
const size_t aMinSize = (std::min)(aNewSize, mySize);
|
||||
if (myIsOwner)
|
||||
{
|
||||
myPointer = myAllocator.reallocate(myPointer, aNewSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
myPointer = myAllocator.allocate(aNewSize);
|
||||
copyConstruct(aPrevContPnt, aMinSize);
|
||||
}
|
||||
construct(mySize, aNewSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (myIsOwner)
|
||||
myAllocator.deallocate(aPrevContPnt, mySize);
|
||||
myPointer = myAllocator.allocate(aNewSize);
|
||||
construct(0, aNewSize);
|
||||
}
|
||||
mySize = aNewSize;
|
||||
myIsOwner = true;
|
||||
resizeImpl(static_cast<size_t>(theUpper - theLower + 1), theLower, theToCopyData);
|
||||
}
|
||||
|
||||
//! Resizes the array to theSize elements, keeping the lower bound unchanged.
|
||||
//! @param theSize new number of elements
|
||||
//! @param theToCopyData flag to copy existing data into new array
|
||||
void Resize(const size_t theSize, const bool theToCopyData)
|
||||
{
|
||||
resizeImpl(theSize, myLowerBound, theToCopyData);
|
||||
}
|
||||
|
||||
bool IsDeletable() const noexcept { return myIsOwner; }
|
||||
@@ -409,6 +401,52 @@ public:
|
||||
friend iterator;
|
||||
friend const_iterator;
|
||||
|
||||
protected:
|
||||
//! Core resize implementation used by all public Resize() overloads.
|
||||
//! @param theNewSize new number of elements
|
||||
//! @param theNewLower new lower bound value to store
|
||||
//! @param theToCopyData whether to preserve existing elements
|
||||
void resizeImpl(const size_t theNewSize, const int theNewLower, const bool theToCopyData)
|
||||
{
|
||||
const pointer aPrevPtr = myPointer;
|
||||
if (theNewSize == mySize)
|
||||
{
|
||||
myLowerBound = theNewLower;
|
||||
return;
|
||||
}
|
||||
if (myIsOwner)
|
||||
{
|
||||
if (theToCopyData)
|
||||
destroy(myPointer, theNewSize, mySize);
|
||||
else
|
||||
destroy(myPointer, 0, mySize);
|
||||
}
|
||||
myLowerBound = theNewLower;
|
||||
if (theToCopyData)
|
||||
{
|
||||
const size_t aMinSize = (std::min)(theNewSize, mySize);
|
||||
if (myIsOwner)
|
||||
{
|
||||
myPointer = myAllocator.reallocate(myPointer, theNewSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
myPointer = myAllocator.allocate(theNewSize);
|
||||
copyConstruct(aPrevPtr, aMinSize);
|
||||
}
|
||||
construct(mySize < theNewSize ? mySize : theNewSize, theNewSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (myIsOwner)
|
||||
myAllocator.deallocate(aPrevPtr, mySize);
|
||||
myPointer = myAllocator.allocate(theNewSize);
|
||||
construct(0, theNewSize);
|
||||
}
|
||||
mySize = theNewSize;
|
||||
myIsOwner = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
const_reference at(const size_t theIndex) const
|
||||
{
|
||||
@@ -422,7 +460,6 @@ protected:
|
||||
return myPointer[theIndex];
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename U = TheItemType>
|
||||
typename std::enable_if<std::is_trivially_default_constructible<U>::value, void>::type construct(
|
||||
const size_t,
|
||||
|
||||
@@ -39,6 +39,13 @@
|
||||
*
|
||||
* for (i = A.LowerRow(); i <= A.UpperRow(); i++)
|
||||
* for (j = A.LowerCol(); j <= A.UpperCol(); j++)
|
||||
*
|
||||
* Zero-based (size_t) construction mode:
|
||||
* NCollection_Array2(size_t theNbRows, size_t theNbCols) creates a zero-based array
|
||||
* (LowerRow()==0, LowerCol()==0). In this mode At()/ChangeAt() and STL iterators are
|
||||
* the preferred access path -- they address elements directly without any offset subtraction.
|
||||
* Buffer-reuse variant NCollection_Array2(pointer, size_t, size_t) wraps an existing
|
||||
* flat row-major buffer and does NOT own the memory.
|
||||
*/
|
||||
template <class TheItemType>
|
||||
class NCollection_Array2 : public NCollection_Array1<TheItemType>
|
||||
@@ -111,23 +118,6 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
explicit NCollection_Array2(const allocator_type& theAlloc,
|
||||
const int theRowLower,
|
||||
const int theRowUpper,
|
||||
const int theColLower,
|
||||
const int theColUpper)
|
||||
: NCollection_Array1<TheItemType>(
|
||||
theAlloc,
|
||||
BeginPosition(theRowLower, theRowUpper, theColLower, theColUpper),
|
||||
LastPosition(theRowLower, theRowUpper, theColLower, theColUpper)),
|
||||
myLowerRow(theRowLower),
|
||||
mySizeRow(theRowUpper - theRowLower + 1),
|
||||
myLowerCol(theColLower),
|
||||
mySizeCol(theColUpper - theColLower + 1)
|
||||
{
|
||||
}
|
||||
|
||||
//! Copy constructor
|
||||
NCollection_Array2(const NCollection_Array2& theOther)
|
||||
: NCollection_Array1<TheItemType>(theOther),
|
||||
@@ -169,6 +159,29 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
//! Zero-based constructor: allocates theNbRows x theNbCols elements with lower bounds 0.
|
||||
//! Use At()/ChangeAt() or STL iterators for optimal access (no offset subtraction).
|
||||
explicit NCollection_Array2(const size_t theNbRows, const size_t theNbCols)
|
||||
: NCollection_Array1<TheItemType>(theNbRows * theNbCols),
|
||||
myLowerRow(0),
|
||||
mySizeRow(theNbRows),
|
||||
myLowerCol(0),
|
||||
mySizeCol(theNbCols)
|
||||
{
|
||||
}
|
||||
|
||||
//! Zero-based buffer-reuse constructor: wraps an existing flat row-major C array.
|
||||
//! The array does NOT own the buffer and will NOT free it on destruction.
|
||||
//! Use At()/ChangeAt() or STL iterators for optimal access (no offset subtraction).
|
||||
explicit NCollection_Array2(pointer theBegin, const size_t theNbRows, const size_t theNbCols)
|
||||
: NCollection_Array1<TheItemType>(theBegin, theNbRows * theNbCols),
|
||||
myLowerRow(0),
|
||||
mySizeRow(theNbRows),
|
||||
myLowerCol(0),
|
||||
mySizeCol(theNbCols)
|
||||
{
|
||||
}
|
||||
|
||||
//! Size (number of items).
|
||||
size_t Size() const noexcept { return mySizeRow * mySizeCol; }
|
||||
|
||||
@@ -387,6 +400,34 @@ public:
|
||||
resizeImpl<true>(theRowLower, theRowUpper, theColLower, theColUpper);
|
||||
}
|
||||
|
||||
//! Zero-based Resize: resizes to theNbRows x theNbCols, keeping lower bounds unchanged.
|
||||
//! No re-allocation is done if dimensions are unchanged.
|
||||
//! @param theNbRows new number of rows
|
||||
//! @param theNbCols new number of columns
|
||||
//! @param theToCopyData flag to copy existing data into new array
|
||||
void Resize(const size_t theNbRows, const size_t theNbCols, const bool theToCopyData)
|
||||
{
|
||||
Resize(myLowerRow,
|
||||
myLowerRow + static_cast<int>(theNbRows) - 1,
|
||||
myLowerCol,
|
||||
myLowerCol + static_cast<int>(theNbCols) - 1,
|
||||
theToCopyData);
|
||||
}
|
||||
|
||||
//! Zero-based ResizeWithTrim: resizes preserving 2D layout, keeping lower bounds unchanged.
|
||||
//! No re-allocation is done if dimensions are unchanged.
|
||||
//! @param theNbRows new number of rows
|
||||
//! @param theNbCols new number of columns
|
||||
//! @param theToCopyData flag to copy existing data into new array
|
||||
void ResizeWithTrim(const size_t theNbRows, const size_t theNbCols, const bool theToCopyData)
|
||||
{
|
||||
ResizeWithTrim(myLowerRow,
|
||||
myLowerRow + static_cast<int>(theNbRows) - 1,
|
||||
myLowerCol,
|
||||
myLowerCol + static_cast<int>(theNbCols) - 1,
|
||||
theToCopyData);
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Resize without copying data.
|
||||
void resizeNoData(int theRowLower, int theRowUpper, int theColLower, int theColUpper)
|
||||
|
||||
Reference in New Issue
Block a user