Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-17 09:21:22

0001 // Copyright (c) 2002-2023 OPEN CASCADE SAS
0002 //
0003 // This file is part of Open CASCADE Technology software library.
0004 //
0005 // This library is free software; you can redistribute it and/or modify it under
0006 // the terms of the GNU Lesser General Public License version 2.1 as published
0007 // by the Free Software Foundation, with special exception defined in the file
0008 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0009 // distribution for complete text of the license and disclaimer of any warranty.
0010 //
0011 // Alternatively, this file may be used under the terms of Open CASCADE
0012 // commercial license or contractual agreement.
0013 
0014 #ifndef NCollection_DynamicArray_HeaderFile
0015 #define NCollection_DynamicArray_HeaderFile
0016 
0017 #include <NCollection_Allocator.hxx>
0018 #include <NCollection_LinearVector.hxx>
0019 #include <Standard_DimensionMismatch.hxx>
0020 #include <Standard_OutOfMemory.hxx>
0021 #include <Standard_NotImplemented.hxx>
0022 #include <Standard_OutOfRange.hxx>
0023 
0024 #include <NCollection_DefineAlloc.hxx>
0025 #include <NCollection_Iterator.hxx>
0026 #include <NCollection_OccAllocator.hxx>
0027 #include <StdFail_NotDone.hxx>
0028 
0029 #include <cstring>
0030 #include <locale>
0031 #include <type_traits>
0032 #include <vector>
0033 
0034 //! Class NCollection_DynamicArray (dynamic array of objects)
0035 //!
0036 //! The array's indices always start at 0.
0037 //!
0038 //! The Vector is always created with 0 length. It can be enlarged by two means:
0039 //!  1. Calling the method Append (val) - then "val" is added to the end of the
0040 //!     vector (the vector length is incremented)
0041 //!  2. Calling the method SetValue (i, val) - if "i" is greater than or equal
0042 //!     to the current length of the vector, the vector is enlarged to accomo-
0043 //!     date this index
0044 //!
0045 //! The methods Append and SetValue return a non-const reference to the copied
0046 //! object inside the vector. This reference is guaranteed to be valid until
0047 //! the vector is destroyed. It can be used to access the vector member directly
0048 //! or to pass its address to other data structures.
0049 //!
0050 //! The vector iterator remembers the length of the vector at the moment of the
0051 //! creation or initialisation of the iterator. Therefore the iteration begins
0052 //! at index 0 and stops at the index equal to (remembered_length-1). It is OK
0053 //! to enlarge the vector during the iteration.
0054 template <class TheItemType>
0055 class NCollection_DynamicArray
0056 {
0057 public:
0058   //! Memory allocation
0059   DEFINE_STANDARD_ALLOC;
0060   DEFINE_NCOLLECTION_ALLOC;
0061 
0062 public:
0063   typedef NCollection_OccAllocator<TheItemType>  allocator_type;
0064   typedef NCollection_LinearVector<TheItemType*> vector;
0065 
0066 public:
0067   // Define various type aliases for convenience
0068   using value_type      = TheItemType;
0069   using size_type       = size_t;
0070   using difference_type = size_t;
0071   using pointer         = TheItemType*;
0072   using const_pointer   = const TheItemType*;
0073   using reference       = TheItemType&;
0074   using const_reference = const TheItemType&;
0075 
0076 public:
0077   template <bool IsConstant>
0078   class DynamicIterator
0079   {
0080   public:
0081     using iterator_category = std::random_access_iterator_tag;
0082     using value_type        = TheItemType;
0083     using difference_type   = ptrdiff_t;
0084     using pointer   = typename std::conditional<IsConstant, const TheItemType*, TheItemType*>::type;
0085     using reference = typename std::conditional<IsConstant, const TheItemType&, TheItemType&>::type;
0086 
0087   public:
0088     DynamicIterator() noexcept
0089         : myOwner(nullptr),
0090           myIndex(0),
0091           myUsedSize(0),
0092           myInternalSize(1),
0093           myBlockShift(0),
0094           myBlockMask(0),
0095           myBlockIndex(0),
0096           myCurrPtr(nullptr),
0097           myBlockEnd(nullptr)
0098     {
0099     }
0100 
0101     DynamicIterator(const NCollection_DynamicArray& theArray) noexcept
0102         : DynamicIterator(0, theArray)
0103     {
0104     }
0105 
0106     DynamicIterator(const size_t theIndex, const NCollection_DynamicArray& theArray) noexcept
0107         : myOwner(&theArray),
0108           myIndex(theIndex),
0109           myUsedSize(theArray.myUsedSize),
0110           myInternalSize(theArray.myInternalSize),
0111           myBlockShift(theArray.myBlockShift),
0112           myBlockMask(theArray.myBlockMask),
0113           myBlockIndex(0),
0114           myCurrPtr(nullptr),
0115           myBlockEnd(nullptr)
0116     {
0117       setIndex(theIndex);
0118     }
0119 
0120     DynamicIterator(const DynamicIterator<false>& theOther) noexcept
0121         : myOwner(theOther.myOwner),
0122           myIndex(theOther.myIndex),
0123           myUsedSize(theOther.myUsedSize),
0124           myInternalSize(theOther.myInternalSize),
0125           myBlockShift(theOther.myBlockShift),
0126           myBlockMask(theOther.myBlockMask),
0127           myBlockIndex(theOther.myBlockIndex),
0128           myCurrPtr(theOther.myCurrPtr),
0129           myBlockEnd(theOther.myBlockEnd)
0130     {
0131     }
0132 
0133     DynamicIterator& operator=(const DynamicIterator<false>& theOther) noexcept
0134     {
0135       myOwner        = theOther.myOwner;
0136       myIndex        = theOther.myIndex;
0137       myUsedSize     = theOther.myUsedSize;
0138       myInternalSize = theOther.myInternalSize;
0139       myBlockShift   = theOther.myBlockShift;
0140       myBlockMask    = theOther.myBlockMask;
0141       myBlockIndex   = theOther.myBlockIndex;
0142       myCurrPtr      = theOther.myCurrPtr;
0143       myBlockEnd     = theOther.myBlockEnd;
0144       return *this;
0145     }
0146 
0147   public:
0148     bool operator==(const DynamicIterator& theOther) const noexcept
0149     {
0150       return myOwner == theOther.myOwner && myIndex == theOther.myIndex;
0151     }
0152 
0153     template <bool theOtherIsConstant>
0154     bool operator==(const DynamicIterator<theOtherIsConstant>& theOther) const noexcept
0155     {
0156       return myOwner == theOther.myOwner && myIndex == theOther.myIndex;
0157     }
0158 
0159     template <bool theOtherIsConstant>
0160     bool operator!=(const DynamicIterator<theOtherIsConstant>& theOther) const noexcept
0161     {
0162       return myOwner != theOther.myOwner || myIndex != theOther.myIndex;
0163     }
0164 
0165     bool operator!=(const DynamicIterator& theOther) const noexcept { return !(*this == theOther); }
0166 
0167     reference operator*() const noexcept { return *myCurrPtr; }
0168 
0169     pointer operator->() const noexcept { return myCurrPtr; }
0170 
0171     DynamicIterator& operator++() noexcept
0172     {
0173       ++myIndex;
0174       ++myCurrPtr;
0175       if (myIndex >= myUsedSize)
0176       {
0177         myCurrPtr  = nullptr;
0178         myBlockEnd = nullptr;
0179       }
0180       else if (myCurrPtr == myBlockEnd)
0181       {
0182         ++myBlockIndex;
0183         myCurrPtr  = blockStart(myBlockIndex);
0184         myBlockEnd = myCurrPtr + myInternalSize;
0185       }
0186       return *this;
0187     }
0188 
0189     DynamicIterator operator++(int) noexcept
0190     {
0191       DynamicIterator theOld(*this);
0192       ++(*this);
0193       return theOld;
0194     }
0195 
0196     DynamicIterator& operator--() noexcept
0197     {
0198       if (myIndex == myUsedSize)
0199       {
0200         setIndex(myUsedSize - 1);
0201         return *this;
0202       }
0203 
0204       --myIndex;
0205       if (myCurrPtr > blockStart(myBlockIndex))
0206       {
0207         --myCurrPtr;
0208       }
0209       else
0210       {
0211         --myBlockIndex;
0212         myCurrPtr  = blockStart(myBlockIndex) + (myInternalSize - 1);
0213         myBlockEnd = blockStart(myBlockIndex) + myInternalSize;
0214       }
0215       return *this;
0216     }
0217 
0218     DynamicIterator operator--(int) noexcept
0219     {
0220       DynamicIterator theOld(*this);
0221       --(*this);
0222       return theOld;
0223     }
0224 
0225     DynamicIterator& operator+=(const difference_type theOffset) noexcept
0226     {
0227       setIndex(static_cast<size_t>(static_cast<difference_type>(myIndex) + theOffset));
0228       return *this;
0229     }
0230 
0231     DynamicIterator operator+(const difference_type theOffset) const noexcept
0232     {
0233       DynamicIterator aTemp(*this);
0234       aTemp += theOffset;
0235       return aTemp;
0236     }
0237 
0238     DynamicIterator& operator-=(const difference_type theOffset) noexcept
0239     {
0240       return *this += -theOffset;
0241     }
0242 
0243     DynamicIterator operator-(const difference_type theOffset) const noexcept
0244     {
0245       DynamicIterator aTemp(*this);
0246       aTemp += -theOffset;
0247       return aTemp;
0248     }
0249 
0250     difference_type operator-(const DynamicIterator& theOther) const noexcept
0251     {
0252       return static_cast<difference_type>(myIndex) - static_cast<difference_type>(theOther.myIndex);
0253     }
0254 
0255     reference operator[](const difference_type theOffset) const noexcept
0256     {
0257       return *(*this + theOffset);
0258     }
0259 
0260     bool operator<(const DynamicIterator& theOther) const noexcept
0261     {
0262       return (*this - theOther) < 0;
0263     }
0264 
0265     bool operator>(const DynamicIterator& theOther) const noexcept { return theOther < *this; }
0266 
0267     bool operator<=(const DynamicIterator& theOther) const noexcept { return !(theOther < *this); }
0268 
0269     bool operator>=(const DynamicIterator& theOther) const noexcept { return !(*this < theOther); }
0270 
0271     friend DynamicIterator operator+(const difference_type  theOffset,
0272                                      const DynamicIterator& theIter) noexcept
0273     {
0274       return theIter + theOffset;
0275     }
0276 
0277     friend class DynamicIterator<!IsConstant>;
0278 
0279   private:
0280     void setIndex(const size_t theIndex) noexcept
0281     {
0282       myIndex = theIndex;
0283       if (myIndex >= myUsedSize || myOwner == nullptr)
0284       {
0285         myCurrPtr    = nullptr;
0286         myBlockEnd   = nullptr;
0287         myBlockIndex = 0;
0288         return;
0289       }
0290 
0291       myBlockIndex             = myIndex >> myBlockShift;
0292       const size_t aLocalIndex = myIndex & myBlockMask;
0293       myCurrPtr                = blockStart(myBlockIndex) + aLocalIndex;
0294       myBlockEnd               = blockStart(myBlockIndex) + myInternalSize;
0295     }
0296 
0297     TheItemType* blockStart(const size_t theBlockIndex) const noexcept
0298     {
0299       return myOwner->getArray()[theBlockIndex];
0300     }
0301 
0302   private:
0303     const NCollection_DynamicArray* myOwner;
0304     size_t                          myIndex;
0305     size_t                          myUsedSize;
0306     size_t                          myInternalSize;
0307     size_t                          myBlockShift;
0308     size_t                          myBlockMask;
0309     size_t                          myBlockIndex;
0310     TheItemType*                    myCurrPtr;
0311     TheItemType*                    myBlockEnd;
0312   };
0313 
0314   using iterator       = DynamicIterator<false>;
0315   using const_iterator = DynamicIterator<true>;
0316   using Iterator       = NCollection_Iterator<NCollection_DynamicArray<TheItemType>>;
0317 
0318 public:
0319   const_iterator begin() const noexcept { return const_iterator(*this); }
0320 
0321   iterator begin() noexcept { return iterator(*this); }
0322 
0323   const_iterator cbegin() const noexcept { return const_iterator(*this); }
0324 
0325   iterator end() noexcept { return iterator(myUsedSize, *this); }
0326 
0327   const_iterator end() const noexcept { return const_iterator(myUsedSize, *this); }
0328 
0329   const_iterator cend() const noexcept { return const_iterator(myUsedSize, *this); }
0330 
0331 public: //! @name public methods
0332   NCollection_DynamicArray(const size_t theIncrement)
0333       : myAlloc(),
0334         myInternalSize(roundUpPow2(theIncrement)),
0335         myBlockShift(log2Pow2(myInternalSize)),
0336         myBlockMask(myInternalSize - 1),
0337         myUsedSize(0)
0338   {
0339   }
0340 
0341   NCollection_DynamicArray(const int theIncrement = 256)
0342       : NCollection_DynamicArray(static_cast<size_t>(theIncrement < 1 ? 1 : theIncrement))
0343   {
0344   }
0345 
0346   // Constructor taking an allocator
0347   explicit NCollection_DynamicArray(const size_t                                  theIncrement,
0348                                     const occ::handle<NCollection_BaseAllocator>& theAllocator)
0349       : myAlloc(allocator_type(theAllocator)),
0350         myInternalSize(roundUpPow2(theIncrement)),
0351         myBlockShift(log2Pow2(myInternalSize)),
0352         myBlockMask(myInternalSize - 1),
0353         myUsedSize(0)
0354   {
0355   }
0356 
0357   explicit NCollection_DynamicArray(const int                                     theIncrement,
0358                                     const occ::handle<NCollection_BaseAllocator>& theAllocator)
0359       : NCollection_DynamicArray(static_cast<size_t>(theIncrement < 1 ? 1 : theIncrement),
0360                                  theAllocator)
0361   {
0362   }
0363 
0364   // Constructor taking an allocator
0365   explicit NCollection_DynamicArray(const size_t theIncrement, const allocator_type& theAllocator)
0366       : myAlloc(theAllocator),
0367         myInternalSize(roundUpPow2(theIncrement)),
0368         myBlockShift(log2Pow2(myInternalSize)),
0369         myBlockMask(myInternalSize - 1),
0370         myUsedSize(0)
0371   {
0372   }
0373 
0374   explicit NCollection_DynamicArray(const int theIncrement, const allocator_type& theAllocator)
0375       : NCollection_DynamicArray(static_cast<size_t>(theIncrement < 1 ? 1 : theIncrement),
0376                                  theAllocator)
0377   {
0378   }
0379 
0380   //! Copy constructor
0381   NCollection_DynamicArray(const NCollection_DynamicArray& theOther)
0382       : myContainer(theOther.myContainer),
0383         myAlloc(theOther.myAlloc),
0384         myInternalSize(theOther.myInternalSize),
0385         myBlockShift(theOther.myBlockShift),
0386         myBlockMask(theOther.myBlockMask),
0387         myUsedSize(theOther.myUsedSize)
0388   {
0389     copyDate();
0390   }
0391 
0392   NCollection_DynamicArray(NCollection_DynamicArray&& theOther) noexcept
0393       : myContainer(std::move(theOther.myContainer)),
0394         myAlloc(theOther.myAlloc),
0395         myInternalSize(theOther.myInternalSize),
0396         myBlockShift(theOther.myBlockShift),
0397         myBlockMask(theOther.myBlockMask),
0398         myUsedSize(theOther.myUsedSize)
0399   {
0400     theOther.myUsedSize = 0;
0401   }
0402 
0403   ~NCollection_DynamicArray() { Clear(true); }
0404 
0405   //! Total number of items in the vector.
0406   size_t Size() const noexcept { return myUsedSize; }
0407 
0408   //! Total number of items (legacy int-returning API).
0409   int Length() const noexcept { return static_cast<int>(myUsedSize); }
0410 
0411   //! Method for consistency with other collections.
0412   //! @return Lower bound (inclusive) for iteration.
0413   int Lower() const noexcept { return 0; }
0414 
0415   //! Method for consistency with other collections.
0416   //! @return Upper bound (inclusive) for iteration.
0417   int Upper() const noexcept { return static_cast<int>(myUsedSize) - 1; }
0418 
0419   //! Empty query
0420   bool IsEmpty() const noexcept { return myUsedSize == 0; }
0421 
0422   //! Assignment to the collection of the same type
0423   NCollection_DynamicArray& Assign(const NCollection_DynamicArray& theOther,
0424                                    const bool                      theOwnAllocator = true)
0425   {
0426     if (&theOther == this)
0427     {
0428       return *this;
0429     }
0430     if (!theOwnAllocator)
0431     {
0432       Clear(myAlloc != theOther.myAlloc);
0433       myAlloc = theOther.myAlloc;
0434     }
0435     else
0436     {
0437       Clear(false);
0438     }
0439     myContainer    = theOther.myContainer;
0440     myInternalSize = theOther.myInternalSize;
0441     myBlockShift   = theOther.myBlockShift;
0442     myBlockMask    = theOther.myBlockMask;
0443     myUsedSize     = theOther.myUsedSize;
0444     copyDate();
0445     return *this;
0446   }
0447 
0448   NCollection_DynamicArray& Assign(NCollection_DynamicArray&& theOther)
0449   {
0450     if (&theOther == this)
0451     {
0452       return *this;
0453     }
0454     Clear(true);
0455     myContainer         = std::move(theOther.myContainer);
0456     myAlloc             = theOther.myAlloc;
0457     myInternalSize      = theOther.myInternalSize;
0458     myBlockShift        = theOther.myBlockShift;
0459     myBlockMask         = theOther.myBlockMask;
0460     myUsedSize          = theOther.myUsedSize;
0461     theOther.myUsedSize = 0;
0462     return *this;
0463   }
0464 
0465   //! Assignment operator
0466   NCollection_DynamicArray& operator=(const NCollection_DynamicArray& theOther)
0467   {
0468     return Assign(theOther, false);
0469   }
0470 
0471   //! Assignment operator
0472   NCollection_DynamicArray& operator=(NCollection_DynamicArray&& theOther) noexcept
0473   {
0474     return Assign(std::forward<NCollection_DynamicArray>(theOther));
0475   }
0476 
0477   //! Append
0478   reference Append(const TheItemType& theValue)
0479   {
0480     if (myUsedSize >= availableSize())
0481     {
0482       expandArray();
0483     }
0484     pointer aPnt = &at(myUsedSize++);
0485     myAlloc.construct(aPnt, theValue);
0486     return *aPnt;
0487   }
0488 
0489   //! Append
0490   reference Append(TheItemType&& theValue)
0491   {
0492     if (myUsedSize >= availableSize())
0493     {
0494       expandArray();
0495     }
0496     pointer aPnt = &at(myUsedSize++);
0497     myAlloc.construct(aPnt, std::forward<TheItemType>(theValue));
0498     return *aPnt;
0499   }
0500 
0501   //! Insert a value after the element at theIndex, shifting subsequent elements right.
0502   //! @param theIndex index after which to insert (must be in [0, Size()-1])
0503   //! @param theValue value to insert
0504   //! @return reference to the inserted element
0505   reference InsertAfter(const size_t theIndex, const TheItemType& theValue)
0506   {
0507     Standard_OutOfRange_Raise_if(theIndex >= myUsedSize,
0508                                  "NCollection_DynamicArray::InsertAfter: index out of range");
0509     Appended();
0510     for (size_t i = myUsedSize - 1; i > theIndex + 1; --i)
0511     {
0512       at(i) = std::move(at(i - 1));
0513     }
0514     at(theIndex + 1) = theValue;
0515     return at(theIndex + 1);
0516   }
0517 
0518   //! Insert a value after the element at theIndex (move version).
0519   reference InsertAfter(const size_t theIndex, TheItemType&& theValue)
0520   {
0521     Standard_OutOfRange_Raise_if(theIndex >= myUsedSize,
0522                                  "NCollection_DynamicArray::InsertAfter: index out of range");
0523     Appended();
0524     for (size_t i = myUsedSize - 1; i > theIndex + 1; --i)
0525     {
0526       at(i) = std::move(at(i - 1));
0527     }
0528     at(theIndex + 1) = std::forward<TheItemType>(theValue);
0529     return at(theIndex + 1);
0530   }
0531 
0532   reference InsertAfter(const int theIndex, const TheItemType& theValue)
0533   {
0534     Standard_OutOfRange_Raise_if(theIndex < 0,
0535                                  "NCollection_DynamicArray::InsertAfter: index out of range");
0536     return InsertAfter(static_cast<size_t>(theIndex), theValue);
0537   }
0538 
0539   reference InsertAfter(const int theIndex, TheItemType&& theValue)
0540   {
0541     Standard_OutOfRange_Raise_if(theIndex < 0,
0542                                  "NCollection_DynamicArray::InsertAfter: index out of range");
0543     return InsertAfter(static_cast<size_t>(theIndex), std::forward<TheItemType>(theValue));
0544   }
0545 
0546   //! Insert a value before the element at theIndex, shifting it and subsequent elements right.
0547   //! @param theIndex index before which to insert (must be in [0, Size()-1])
0548   //! @param theValue value to insert
0549   //! @return reference to the inserted element
0550   reference InsertBefore(const size_t theIndex, const TheItemType& theValue)
0551   {
0552     Standard_OutOfRange_Raise_if(theIndex >= myUsedSize,
0553                                  "NCollection_DynamicArray::InsertBefore: index out of range");
0554     Appended();
0555     for (size_t i = myUsedSize - 1; i > theIndex; --i)
0556     {
0557       at(i) = std::move(at(i - 1));
0558     }
0559     at(theIndex) = theValue;
0560     return at(theIndex);
0561   }
0562 
0563   //! Insert a value before the element at theIndex (move version).
0564   reference InsertBefore(const size_t theIndex, TheItemType&& theValue)
0565   {
0566     Standard_OutOfRange_Raise_if(theIndex >= myUsedSize,
0567                                  "NCollection_DynamicArray::InsertBefore: index out of range");
0568     Appended();
0569     for (size_t i = myUsedSize - 1; i > theIndex; --i)
0570     {
0571       at(i) = std::move(at(i - 1));
0572     }
0573     at(theIndex) = std::forward<TheItemType>(theValue);
0574     return at(theIndex);
0575   }
0576 
0577   reference InsertBefore(const int theIndex, const TheItemType& theValue)
0578   {
0579     Standard_OutOfRange_Raise_if(theIndex < 0,
0580                                  "NCollection_DynamicArray::InsertBefore: index out of range");
0581     return InsertBefore(static_cast<size_t>(theIndex), theValue);
0582   }
0583 
0584   reference InsertBefore(const int theIndex, TheItemType&& theValue)
0585   {
0586     Standard_OutOfRange_Raise_if(theIndex < 0,
0587                                  "NCollection_DynamicArray::InsertBefore: index out of range");
0588     return InsertBefore(static_cast<size_t>(theIndex), std::forward<TheItemType>(theValue));
0589   }
0590 
0591   void EraseLast()
0592   {
0593     if (myUsedSize == 0)
0594     {
0595       return;
0596     }
0597     if constexpr (!std::is_trivially_destructible_v<TheItemType>)
0598     {
0599       TheItemType* aLastElem = &ChangeLast();
0600       myAlloc.destroy(aLastElem);
0601     }
0602     myUsedSize--;
0603   }
0604 
0605   //! Appends an empty value and returns the reference to it
0606   reference Appended()
0607   {
0608     if (myUsedSize >= availableSize())
0609     {
0610       expandArray();
0611     }
0612     pointer aPnt = &at(myUsedSize++);
0613     myAlloc.construct(aPnt);
0614     return *aPnt;
0615   }
0616 
0617   //! Emplace one item at the end, constructing it in-place
0618   //! @param theArgs arguments forwarded to TheItemType constructor
0619   //! @return reference to the newly constructed item
0620   template <typename... Args>
0621   reference EmplaceAppend(Args&&... theArgs)
0622   {
0623     if (myUsedSize >= availableSize())
0624     {
0625       expandArray();
0626     }
0627     pointer aPnt = &at(myUsedSize++);
0628     myAlloc.construct(aPnt, std::forward<Args>(theArgs)...);
0629     return *aPnt;
0630   }
0631 
0632   //! Emplace value at the specified index, constructing it in-place
0633   //! If the index is beyond current size, default-constructs intermediate elements
0634   //! @param theIndex index at which to emplace the value
0635   //! @param theArgs arguments forwarded to TheItemType constructor
0636   //! @return reference to the newly constructed item
0637   template <typename... Args>
0638   reference EmplaceValue(const size_t theIndex, Args&&... theArgs)
0639   {
0640     ensureStorageForIndex(theIndex);
0641     const bool isExisting = theIndex < myUsedSize;
0642     if (!isExisting)
0643     {
0644       for (; myUsedSize < theIndex; myUsedSize++)
0645       {
0646         pointer aPnt = &at(myUsedSize);
0647         myAlloc.construct(aPnt);
0648       }
0649       myUsedSize++;
0650     }
0651     pointer aPnt = &at(theIndex);
0652     if (isExisting)
0653     {
0654       if constexpr (!std::is_trivially_destructible_v<TheItemType>)
0655       {
0656         myAlloc.destroy(aPnt);
0657       }
0658     }
0659     myAlloc.construct(aPnt, std::forward<Args>(theArgs)...);
0660     return *aPnt;
0661   }
0662 
0663   template <typename... Args>
0664   reference EmplaceValue(const int theIndex, Args&&... theArgs)
0665   {
0666     Standard_OutOfRange_Raise_if(theIndex < 0,
0667                                  "NCollection_DynamicArray::EmplaceValue: index out of range");
0668     return EmplaceValue(static_cast<size_t>(theIndex), std::forward<Args>(theArgs)...);
0669   }
0670 
0671   //! Operator() - query the const value
0672   const_reference operator()(const size_t theIndex) const noexcept { return at(theIndex); }
0673 
0674   const_reference operator()(const int theIndex) const noexcept
0675   {
0676     return at(static_cast<size_t>(theIndex));
0677   }
0678 
0679   //! Operator[] - query the const value
0680   const_reference operator[](const size_t theIndex) const noexcept { return at(theIndex); }
0681 
0682   const_reference operator[](const int theIndex) const noexcept
0683   {
0684     return at(static_cast<size_t>(theIndex));
0685   }
0686 
0687   const_reference Value(const size_t theIndex) const noexcept { return at(theIndex); }
0688 
0689   const_reference Value(const int theIndex) const noexcept
0690   {
0691     return at(static_cast<size_t>(theIndex));
0692   }
0693 
0694   //! @return first element
0695   const_reference First() const noexcept { return getArray()[0][0]; }
0696 
0697   //! @return first element
0698   reference ChangeFirst() noexcept { return getArray()[0][0]; }
0699 
0700   //! @return last element
0701   const_reference Last() const noexcept { return at(myUsedSize - 1); }
0702 
0703   //! @return last element
0704   reference ChangeLast() noexcept { return at(myUsedSize - 1); }
0705 
0706   //! Operator() - query the value
0707   reference operator()(const size_t theIndex) noexcept { return at(theIndex); }
0708 
0709   reference operator()(const int theIndex) noexcept { return at(static_cast<size_t>(theIndex)); }
0710 
0711   //! Operator[] - query the value
0712   reference operator[](const size_t theIndex) noexcept { return at(theIndex); }
0713 
0714   reference operator[](const int theIndex) noexcept { return at(static_cast<size_t>(theIndex)); }
0715 
0716   reference ChangeValue(const size_t theIndex) noexcept { return at(theIndex); }
0717 
0718   reference ChangeValue(const int theIndex) noexcept { return at(static_cast<size_t>(theIndex)); }
0719 
0720   //! SetValue () - set or append a value
0721   reference SetValue(const size_t theIndex, const TheItemType& theValue)
0722   {
0723     ensureStorageForIndex(theIndex);
0724     const bool isExisting = theIndex < myUsedSize;
0725     if (!isExisting)
0726     {
0727       for (; myUsedSize < theIndex; myUsedSize++)
0728       {
0729         pointer aPnt = &at(myUsedSize);
0730         myAlloc.construct(aPnt);
0731       }
0732       myUsedSize++;
0733     }
0734     pointer aPnt = &at(theIndex);
0735     if (isExisting)
0736     {
0737       if constexpr (!std::is_trivially_destructible_v<TheItemType>)
0738       {
0739         myAlloc.destroy(aPnt);
0740       }
0741     }
0742     myAlloc.construct(aPnt, theValue);
0743     return *aPnt;
0744   }
0745 
0746   //! SetValue () - set or append a value
0747   reference SetValue(const size_t theIndex, TheItemType&& theValue)
0748   {
0749     ensureStorageForIndex(theIndex);
0750     const bool isExisting = theIndex < myUsedSize;
0751     if (!isExisting)
0752     {
0753       for (; myUsedSize < theIndex; myUsedSize++)
0754       {
0755         pointer aPnt = &at(myUsedSize);
0756         myAlloc.construct(aPnt);
0757       }
0758       myUsedSize++;
0759     }
0760     pointer aPnt = &at(theIndex);
0761     if (isExisting)
0762     {
0763       if constexpr (!std::is_trivially_destructible_v<TheItemType>)
0764       {
0765         myAlloc.destroy(aPnt);
0766       }
0767     }
0768     myAlloc.construct(aPnt, std::forward<TheItemType>(theValue));
0769     return *aPnt;
0770   }
0771 
0772   reference SetValue(const int theIndex, const TheItemType& theValue)
0773   {
0774     Standard_OutOfRange_Raise_if(theIndex < 0,
0775                                  "NCollection_DynamicArray::SetValue: index out of range");
0776     return SetValue(static_cast<size_t>(theIndex), theValue);
0777   }
0778 
0779   reference SetValue(const int theIndex, TheItemType&& theValue)
0780   {
0781     Standard_OutOfRange_Raise_if(theIndex < 0,
0782                                  "NCollection_DynamicArray::SetValue: index out of range");
0783     return SetValue(static_cast<size_t>(theIndex), std::forward<TheItemType>(theValue));
0784   }
0785 
0786   void Clear(const bool theReleaseMemory = false)
0787   {
0788     for (size_t aBlockInd = 0; aBlockInd < myContainer.Size(); aBlockInd++)
0789     {
0790       TheItemType* aCurStart = getArray()[aBlockInd];
0791       if constexpr (!std::is_trivially_destructible_v<TheItemType>)
0792       {
0793         const size_t aBlockStart = aBlockInd * myInternalSize;
0794         const size_t aCount      = (myUsedSize > aBlockStart + myInternalSize)
0795                                      ? myInternalSize
0796                                      : (myUsedSize > aBlockStart ? myUsedSize - aBlockStart : 0);
0797         for (size_t anElemInd = 0; anElemInd < aCount; anElemInd++)
0798         {
0799           aCurStart[anElemInd].~TheItemType();
0800         }
0801       }
0802       if (theReleaseMemory)
0803       {
0804         myAlloc.deallocate(aCurStart, myInternalSize);
0805       }
0806     }
0807     if (theReleaseMemory)
0808     {
0809       myContainer.Clear(theReleaseMemory);
0810     }
0811     myUsedSize = 0;
0812   }
0813 
0814   void SetIncrement(const size_t theIncrement) noexcept
0815   {
0816     if (myUsedSize != 0)
0817     {
0818       return;
0819     }
0820     myInternalSize = roundUpPow2(theIncrement);
0821     myBlockShift   = log2Pow2(myInternalSize);
0822     myBlockMask    = myInternalSize - 1;
0823   }
0824 
0825   void SetIncrement(const int theIncrement) noexcept
0826   {
0827     SetIncrement(static_cast<size_t>(theIncrement < 1 ? 1 : theIncrement));
0828   }
0829 
0830   friend iterator;
0831   friend const_iterator;
0832 
0833 protected:
0834   size_t availableSize() const noexcept
0835   {
0836     return static_cast<size_t>(myContainer.Size()) << myBlockShift;
0837   }
0838 
0839   //! Ensure storage blocks exist to access theIndex.
0840   void ensureStorageForIndex(const size_t theIndex)
0841   {
0842     const size_t aRequiredBlocks = (theIndex >> myBlockShift) + 1;
0843     ensureBlockCount(aRequiredBlocks);
0844   }
0845 
0846   //! Ensure at least theBlockCount blocks are allocated in myContainer.
0847   void ensureBlockCount(const size_t theBlockCount)
0848   {
0849     if (theBlockCount > myContainer.Capacity())
0850     {
0851       myContainer.Reserve(theBlockCount);
0852     }
0853     while (myContainer.Size() < theBlockCount)
0854     {
0855       expandArray();
0856     }
0857   }
0858 
0859   TheItemType* expandArray()
0860   {
0861     TheItemType* aNewBlock = myAlloc.allocate(myInternalSize);
0862     myContainer.Append(aNewBlock);
0863     return aNewBlock;
0864   }
0865 
0866   reference at(const size_t theInd) noexcept
0867   {
0868     return getArray()[theInd >> myBlockShift][theInd & myBlockMask];
0869   }
0870 
0871   const_reference at(const size_t theInd) const noexcept
0872   {
0873     return getArray()[theInd >> myBlockShift][theInd & myBlockMask];
0874   }
0875 
0876   void copyDate()
0877   {
0878     size_t aUsedSize = 0;
0879     for (size_t aBlockInd = 0; aBlockInd < myContainer.Size(); aBlockInd++)
0880     {
0881       TheItemType* aCurStart = getArray()[aBlockInd];
0882       TheItemType* aNewBlock = myAlloc.allocate(myInternalSize);
0883       if constexpr (std::is_trivially_copyable_v<TheItemType>)
0884       {
0885         const size_t aCount =
0886           (myUsedSize - aUsedSize < myInternalSize) ? myUsedSize - aUsedSize : myInternalSize;
0887         std::memcpy(aNewBlock, aCurStart, aCount * sizeof(TheItemType));
0888         aUsedSize += aCount;
0889       }
0890       else
0891       {
0892         for (size_t anElemInd = 0; anElemInd < myInternalSize && aUsedSize < myUsedSize;
0893              anElemInd++, aUsedSize++)
0894         {
0895           pointer aPnt = &aNewBlock[anElemInd];
0896           myAlloc.construct(aPnt, aCurStart[anElemInd]);
0897         }
0898       }
0899       getArray()[aBlockInd] = aNewBlock;
0900     }
0901   }
0902 
0903   //! Wrapper to extract array of block pointers.
0904   TheItemType** getArray() noexcept { return myContainer.IsEmpty() ? nullptr : &myContainer[0]; }
0905 
0906   //! Wrapper to extract array of block pointers (const overload).
0907   TheItemType* const* getArray() const noexcept
0908   {
0909     return myContainer.IsEmpty() ? nullptr : &myContainer[0];
0910   }
0911 
0912   //! Round up to the nearest power of 2 (returns theValue if already power of 2).
0913   //! Works correctly for both 32-bit and 64-bit size_t.
0914   static constexpr size_t roundUpPow2(const size_t theValue) noexcept
0915   {
0916     size_t v = (theValue < 1 ? 1 : theValue);
0917     v--;
0918     v |= v >> 1;
0919     v |= v >> 2;
0920     v |= v >> 4;
0921     v |= v >> 8;
0922     v |= v >> 16;
0923     if constexpr (sizeof(size_t) > 4)
0924     {
0925       v |= v >> 32;
0926     }
0927     v++;
0928     return v;
0929   }
0930 
0931   //! Compute log2 of a power-of-2 value.
0932   static constexpr size_t log2Pow2(const size_t theValue) noexcept
0933   {
0934     size_t aShift = 0;
0935     size_t v      = theValue;
0936     while (v > 1)
0937     {
0938       v >>= 1;
0939       ++aShift;
0940     }
0941     return aShift;
0942   }
0943 
0944 protected:
0945   vector         myContainer;
0946   allocator_type myAlloc;
0947   size_t         myInternalSize;
0948   size_t         myBlockShift; //!< log2(myInternalSize) for fast index-to-block mapping
0949   size_t         myBlockMask;  //!< myInternalSize - 1 for fast index-within-block mapping
0950   size_t         myUsedSize;
0951 };
0952 
0953 #endif // NCollection_DynamicArray_HeaderFile