File indexing completed on 2026-09-13 09:17:14
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef NCollection_LinearVector_HeaderFile
0015 #define NCollection_LinearVector_HeaderFile
0016
0017 #include <NCollection_Allocator.hxx>
0018 #include <NCollection_Array1.hxx>
0019 #include <Standard_OutOfMemory.hxx>
0020 #include <Standard_OutOfRange.hxx>
0021
0022 #include <algorithm>
0023 #include <cstddef>
0024 #include <cstring>
0025 #include <limits>
0026 #include <type_traits>
0027 #include <utility>
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 template <typename TheItemType>
0048 class NCollection_LinearVector
0049 {
0050 public:
0051 using value_type = TheItemType;
0052 using size_type = size_t;
0053 using pointer = TheItemType*;
0054 using const_pointer = const TheItemType*;
0055 using reference = TheItemType&;
0056 using const_reference = const TheItemType&;
0057 using iterator = TheItemType*;
0058 using const_iterator = const TheItemType*;
0059 using allocator_type = NCollection_Allocator<TheItemType>;
0060
0061 public:
0062
0063 NCollection_LinearVector() noexcept = default;
0064
0065
0066
0067
0068
0069 explicit NCollection_LinearVector(const size_t theCapacity)
0070 {
0071 if (theCapacity > 0)
0072 {
0073 myData = myAlloc.allocate(theCapacity);
0074 myCapacity = theCapacity;
0075 }
0076 }
0077
0078
0079
0080
0081
0082 NCollection_LinearVector(const size_t theSize, const TheItemType& theValue)
0083 {
0084 Resize(theSize, theValue);
0085 }
0086
0087
0088 NCollection_LinearVector(const NCollection_LinearVector& theOther)
0089 {
0090 if (theOther.mySize > 0)
0091 {
0092 myData = myAlloc.allocate(theOther.mySize);
0093 myCapacity = theOther.mySize;
0094 mySize = theOther.mySize;
0095 if constexpr (std::is_trivially_copyable_v<TheItemType>)
0096 {
0097 std::memcpy(myData, theOther.myData, mySize * sizeof(TheItemType));
0098 }
0099 else
0100 {
0101 for (size_t i = 0; i < mySize; ++i)
0102 {
0103 myAlloc.construct(myData + i, theOther.myData[i]);
0104 }
0105 }
0106 }
0107 }
0108
0109
0110 NCollection_LinearVector(NCollection_LinearVector&& theOther) noexcept
0111 : myData(theOther.myData),
0112 mySize(theOther.mySize),
0113 myCapacity(theOther.myCapacity)
0114 {
0115 theOther.myData = nullptr;
0116 theOther.mySize = 0;
0117 theOther.myCapacity = 0;
0118 }
0119
0120
0121 ~NCollection_LinearVector() { Clear(true); }
0122
0123
0124 NCollection_LinearVector& operator=(const NCollection_LinearVector& theOther)
0125 {
0126 if (this != &theOther)
0127 {
0128 if (theOther.mySize > myCapacity)
0129 {
0130 NCollection_LinearVector aTmp(theOther);
0131 *this = std::move(aTmp);
0132 return *this;
0133 }
0134
0135 if constexpr (std::is_trivially_copyable_v<TheItemType>)
0136 {
0137 if (theOther.mySize > 0)
0138 {
0139 std::memcpy(myData, theOther.myData, theOther.mySize * sizeof(TheItemType));
0140 }
0141 }
0142 else
0143 {
0144 const size_t aCommonSize = std::min(mySize, theOther.mySize);
0145 for (size_t i = 0; i < aCommonSize; ++i)
0146 {
0147 myData[i] = theOther.myData[i];
0148 }
0149 for (size_t i = aCommonSize; i < theOther.mySize; ++i)
0150 {
0151 myAlloc.construct(myData + i, theOther.myData[i]);
0152 }
0153 destroyRange(theOther.mySize, mySize);
0154 }
0155 mySize = theOther.mySize;
0156 }
0157 return *this;
0158 }
0159
0160
0161 NCollection_LinearVector& operator=(NCollection_LinearVector&& theOther) noexcept
0162 {
0163 if (this != &theOther)
0164 {
0165 Clear(true);
0166 myData = theOther.myData;
0167 mySize = theOther.mySize;
0168 myCapacity = theOther.myCapacity;
0169 theOther.myData = nullptr;
0170 theOther.mySize = 0;
0171 theOther.myCapacity = 0;
0172 }
0173 return *this;
0174 }
0175
0176
0177 TheItemType* Data() noexcept { return myData; }
0178
0179
0180 const TheItemType* Data() const noexcept { return myData; }
0181
0182
0183 bool HasData() const noexcept { return myData != nullptr; }
0184
0185
0186 bool Empty() const noexcept { return IsEmpty(); }
0187
0188
0189 static constexpr size_t MaxSize() noexcept { return std::numeric_limits<size_t>::max(); }
0190
0191
0192 size_t Size() const noexcept { return mySize; }
0193
0194
0195 bool IsEmpty() const noexcept { return mySize == 0; }
0196
0197
0198 size_t Capacity() const noexcept { return myCapacity; }
0199
0200
0201
0202 void Reserve(const size_t theCapacity)
0203 {
0204 if (theCapacity > myCapacity)
0205 {
0206 grow(theCapacity);
0207 }
0208 }
0209
0210
0211
0212
0213
0214 void Resize(const size_t theSize) { Resize(theSize, TheItemType()); }
0215
0216
0217
0218
0219
0220
0221 void Resize(const size_t theSize, const TheItemType& theValue)
0222 {
0223 if (theSize > mySize)
0224 {
0225 if (theSize > myCapacity)
0226 {
0227 grow(theSize);
0228 }
0229 for (size_t i = mySize; i < theSize; ++i)
0230 {
0231 myAlloc.construct(myData + i, theValue);
0232 }
0233 }
0234 else if (theSize < mySize)
0235 {
0236 destroyRange(theSize, mySize);
0237 }
0238 mySize = theSize;
0239 }
0240
0241
0242
0243 const TheItemType& Value(const size_t theIndex) const
0244 {
0245 Standard_OutOfRange_Raise_if(theIndex >= mySize, "NCollection_LinearVector::Value");
0246 return myData[theIndex];
0247 }
0248
0249
0250
0251 TheItemType& ChangeValue(const size_t theIndex)
0252 {
0253 Standard_OutOfRange_Raise_if(theIndex >= mySize, "NCollection_LinearVector::ChangeValue");
0254 return myData[theIndex];
0255 }
0256
0257
0258 const TheItemType& operator()(const size_t theIndex) const { return myData[theIndex]; }
0259
0260
0261 TheItemType& operator()(const size_t theIndex) { return myData[theIndex]; }
0262
0263
0264 const TheItemType& operator[](const size_t theIndex) const { return myData[theIndex]; }
0265
0266
0267 TheItemType& operator[](const size_t theIndex) { return myData[theIndex]; }
0268
0269
0270 const TheItemType& First() const
0271 {
0272 Standard_OutOfRange_Raise_if(mySize == 0, "NCollection_LinearVector::First");
0273 return myData[0];
0274 }
0275
0276
0277 TheItemType& ChangeFirst()
0278 {
0279 Standard_OutOfRange_Raise_if(mySize == 0, "NCollection_LinearVector::ChangeFirst");
0280 return myData[0];
0281 }
0282
0283
0284 const TheItemType& Last() const
0285 {
0286 Standard_OutOfRange_Raise_if(mySize == 0, "NCollection_LinearVector::Last");
0287 return myData[mySize - 1];
0288 }
0289
0290
0291 TheItemType& ChangeLast()
0292 {
0293 Standard_OutOfRange_Raise_if(mySize == 0, "NCollection_LinearVector::ChangeLast");
0294 return myData[mySize - 1];
0295 }
0296
0297
0298
0299
0300 TheItemType& Append(const TheItemType& theValue)
0301 {
0302 if (mySize == myCapacity)
0303 {
0304 grow(mySize + 1);
0305 }
0306 myAlloc.construct(myData + mySize, theValue);
0307 return myData[mySize++];
0308 }
0309
0310
0311
0312
0313 TheItemType& Append(TheItemType&& theValue)
0314 {
0315 if (mySize == myCapacity)
0316 {
0317 grow(mySize + 1);
0318 }
0319 myAlloc.construct(myData + mySize, std::move(theValue));
0320 return myData[mySize++];
0321 }
0322
0323
0324
0325 TheItemType& Appended()
0326 {
0327 if (mySize == myCapacity)
0328 {
0329 grow(mySize + 1);
0330 }
0331 myAlloc.construct(myData + mySize, TheItemType());
0332 return myData[mySize++];
0333 }
0334
0335
0336
0337
0338 template <class... Args>
0339 TheItemType& EmplaceAppend(Args&&... theArgs)
0340 {
0341 if (mySize == myCapacity)
0342 {
0343 grow(mySize + 1);
0344 }
0345 myAlloc.construct(myData + mySize, std::forward<Args>(theArgs)...);
0346 return myData[mySize++];
0347 }
0348
0349
0350
0351
0352
0353 TheItemType& SetValue(const size_t theIndex, const TheItemType& theValue)
0354 {
0355 if (theIndex >= mySize)
0356 {
0357 Resize(theIndex + 1);
0358 }
0359 myData[theIndex] = theValue;
0360 return myData[theIndex];
0361 }
0362
0363
0364
0365
0366
0367 TheItemType& SetValue(const size_t theIndex, TheItemType&& theValue)
0368 {
0369 if (theIndex >= mySize)
0370 {
0371 Resize(theIndex + 1);
0372 }
0373 myData[theIndex] = std::move(theValue);
0374 return myData[theIndex];
0375 }
0376
0377
0378
0379
0380 void InsertBefore(const size_t theIndex, const TheItemType& theValue)
0381 {
0382 Standard_OutOfRange_Raise_if(theIndex > mySize, "NCollection_LinearVector::InsertBefore");
0383 if (mySize == myCapacity)
0384 {
0385 grow(mySize + 1);
0386 }
0387 if (theIndex < mySize)
0388 {
0389 shiftRight(theIndex, 1);
0390 }
0391 myAlloc.construct(myData + theIndex, theValue);
0392 ++mySize;
0393 }
0394
0395
0396
0397
0398 void InsertAfter(const size_t theIndex, const TheItemType& theValue)
0399 {
0400 Standard_OutOfRange_Raise_if(theIndex >= mySize, "NCollection_LinearVector::InsertAfter");
0401 InsertBefore(theIndex + 1, theValue);
0402 }
0403
0404
0405
0406
0407 void InsertBefore(const size_t theIndex, TheItemType&& theValue)
0408 {
0409 Standard_OutOfRange_Raise_if(theIndex > mySize, "NCollection_LinearVector::InsertBefore");
0410 if (mySize == myCapacity)
0411 {
0412 grow(mySize + 1);
0413 }
0414 if (theIndex < mySize)
0415 {
0416 shiftRight(theIndex, 1);
0417 }
0418 myAlloc.construct(myData + theIndex, std::move(theValue));
0419 ++mySize;
0420 }
0421
0422
0423
0424
0425 void InsertAfter(const size_t theIndex, TheItemType&& theValue)
0426 {
0427 Standard_OutOfRange_Raise_if(theIndex >= mySize, "NCollection_LinearVector::InsertAfter");
0428 InsertBefore(theIndex + 1, std::move(theValue));
0429 }
0430
0431
0432 void EraseLast()
0433 {
0434 if (mySize > 0)
0435 {
0436 --mySize;
0437 destroyRange(mySize, mySize + 1);
0438 }
0439 }
0440
0441
0442
0443 void Erase(const size_t theIndex)
0444 {
0445 Standard_OutOfRange_Raise_if(theIndex >= mySize, "NCollection_LinearVector::Erase");
0446
0447
0448
0449
0450
0451 if (theIndex + 1 < mySize)
0452 {
0453 shiftLeft(theIndex, theIndex + 1, mySize);
0454 }
0455 destroyRange(mySize - 1, mySize);
0456 --mySize;
0457 }
0458
0459
0460
0461
0462 void Erase(const size_t theFrom, const size_t theTo)
0463 {
0464 Standard_OutOfRange_Raise_if(theTo > mySize || theFrom >= theTo,
0465 "NCollection_LinearVector::Erase");
0466 const size_t aCount = theTo - theFrom;
0467
0468
0469 if (theTo < mySize)
0470 {
0471 shiftLeft(theFrom, theTo, mySize);
0472 }
0473 destroyRange(mySize - aCount, mySize);
0474 mySize -= aCount;
0475 }
0476
0477
0478
0479 void Clear(const bool theReleaseMemory = false)
0480 {
0481 destroyRange(0, mySize);
0482 mySize = 0;
0483 if (theReleaseMemory && myData != nullptr)
0484 {
0485 myAlloc.deallocate(myData, myCapacity);
0486 myData = nullptr;
0487 myCapacity = 0;
0488 }
0489 }
0490
0491
0492
0493
0494 NCollection_Array1<TheItemType> ToArray1() const
0495 {
0496 return NCollection_Array1<TheItemType>(myData, mySize);
0497 }
0498
0499
0500 iterator begin() noexcept { return myData; }
0501
0502
0503 iterator end() noexcept { return myData + mySize; }
0504
0505
0506 const_iterator begin() const noexcept { return myData; }
0507
0508
0509 const_iterator end() const noexcept { return myData + mySize; }
0510
0511
0512 const_iterator cbegin() const noexcept { return myData; }
0513
0514
0515 const_iterator cend() const noexcept { return myData + mySize; }
0516
0517 private:
0518
0519 void grow(const size_t theMinCapacity)
0520 {
0521 Standard_OutOfMemory_Raise_if(theMinCapacity > MaxSize(), "NCollection_LinearVector::grow");
0522 size_t aNewCap = myCapacity > 0 ? myCapacity * 2 : 2;
0523 if (myCapacity > MaxSize() / 2)
0524 {
0525 aNewCap = MaxSize();
0526 }
0527 if (aNewCap < theMinCapacity)
0528 {
0529 aNewCap = theMinCapacity;
0530 }
0531 if constexpr (std::is_trivially_copyable_v<TheItemType>)
0532 {
0533 myData = myAlloc.reallocate(myData, aNewCap);
0534 }
0535 else
0536 {
0537 TheItemType* aNewData = myAlloc.allocate(aNewCap);
0538 for (size_t i = 0; i < mySize; ++i)
0539 {
0540 myAlloc.construct(aNewData + i, std::move(myData[i]));
0541 myData[i].~TheItemType();
0542 }
0543 if (myData != nullptr)
0544 {
0545 myAlloc.deallocate(myData, myCapacity);
0546 }
0547 myData = aNewData;
0548 }
0549 myCapacity = aNewCap;
0550 }
0551
0552
0553 void destroyRange(const size_t theFrom, const size_t theTo)
0554 {
0555 if constexpr (!std::is_trivially_destructible_v<TheItemType>)
0556 {
0557 for (size_t i = theFrom; i < theTo; ++i)
0558 {
0559 myData[i].~TheItemType();
0560 }
0561 }
0562 }
0563
0564
0565
0566 void shiftRight(const size_t theIndex, const size_t theCount)
0567 {
0568 if constexpr (std::is_trivially_copyable_v<TheItemType>)
0569 {
0570 std::memmove(myData + theIndex + theCount,
0571 myData + theIndex,
0572 (mySize - theIndex) * sizeof(TheItemType));
0573 }
0574 else
0575 {
0576
0577 for (size_t i = mySize; i-- > theIndex;)
0578 {
0579 myAlloc.construct(myData + i + theCount, std::move(myData[i]));
0580 myData[i].~TheItemType();
0581 }
0582 }
0583 }
0584
0585
0586
0587
0588
0589 void shiftLeft(const size_t theDstFrom, const size_t theSrcFrom, const size_t theSrcTo)
0590 {
0591 const size_t aCount = theSrcTo - theSrcFrom;
0592 if constexpr (std::is_trivially_copyable_v<TheItemType>)
0593 {
0594 std::memmove(myData + theDstFrom, myData + theSrcFrom, aCount * sizeof(TheItemType));
0595 }
0596 else
0597 {
0598 for (size_t i = 0; i < aCount; ++i)
0599 {
0600 myData[theDstFrom + i] = std::move(myData[theSrcFrom + i]);
0601 }
0602 }
0603 }
0604
0605 private:
0606 allocator_type myAlloc;
0607 TheItemType* myData = nullptr;
0608 size_t mySize = 0;
0609 size_t myCapacity = 0;
0610 };
0611
0612 #endif