1 // Created on: 2002-04-23
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2002-2013 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #ifndef NCollection_Vector_HeaderFile
17 #define NCollection_Vector_HeaderFile
19 #include <NCollection_BaseVector.hxx>
20 #include <NCollection_StlIterator.hxx>
22 //! Class NCollection_Vector (dynamic array of objects)
24 //! This class is similar to NCollection_Array1 though the indices always start
25 //! at 0 (in Array1 the first index must be specified)
27 //! The Vector is always created with 0 length. It can be enlarged by two means:
28 //! 1. Calling the method Append (val) - then "val" is added to the end of the
29 //! vector (the vector length is incremented)
30 //! 2. Calling the method SetValue (i, val) - if "i" is greater than or equal
31 //! to the current length of the vector, the vector is enlarged to accomo-
34 //! The methods Append and SetValue return a non-const reference to the copied
35 //! object inside the vector. This reference is guaranteed to be valid until
36 //! the vector is destroyed. It can be used to access the vector member directly
37 //! or to pass its address to other data structures.
39 //! The vector iterator remembers the length of the vector at the moment of the
40 //! creation or initialisation of the iterator. Therefore the iteration begins
41 //! at index 0 and stops at the index equal to (remembered_length-1). It is OK
42 //! to enlarge the vector during the iteration.
43 template <class TheItemType>
44 class NCollection_Vector : public NCollection_BaseVector
47 //! STL-compliant typedef for value type
48 typedef TheItemType value_type;
52 //! Nested class Iterator
53 class Iterator : public NCollection_BaseVector::Iterator
57 //! Empty constructor - for later Init
60 //! Constructor with initialisation
61 Iterator (const NCollection_Vector& theVector, Standard_Boolean theToEnd = Standard_False)
62 : NCollection_BaseVector::Iterator (theVector, theToEnd) {}
65 void Init (const NCollection_Vector& theVector)
71 Standard_Boolean More() const
76 //! Increment operator.
82 //! Decrement operator.
89 void Offset (ptrdiff_t theOffset)
91 offsetV (static_cast<int>(theOffset));
94 // Workaround for a bug (endless compilation) occurred in MS Visual Studio 2019 / Win32 / Release configuration
95 // with DISABLED Whole Program Optimization (as it is by default in OCCT). The problem is
96 // at the line std::stable_sort(aPairList.begin(), aPairList.end(), BRepExtrema_CheckPair_Comparator);
97 // of BRepExtrema_DistShapeShape.cxx source file.
98 // To enable Whole Program Optimization use command line keys: /GL for compiler and /LTCG for linker.
99 // Remove this workaround after the bug in VS2019 will be fixed (see OCCT bug #0031628).
100 #if defined (_MSC_VER) && (_MSC_VER >= 1920) && !defined (_WIN64) && !defined (_DEBUG)
101 __declspec(noinline) __declspec(deprecated("TODO remove this workaround for VS2019 compiler hanging bug"))
103 //! Difference operator.
104 ptrdiff_t Differ (const Iterator& theOther) const
106 return differV (theOther);
109 //! Constant value access
110 const TheItemType& Value() const
112 return ((const TheItemType* )curBlockV()->DataPtr)[myCurIndex];
115 //! Variable value access
116 TheItemType& ChangeValue() const
118 return ((TheItemType* )curBlockV()->DataPtr)[myCurIndex];
121 //! Performs comparison of two iterators.
122 Standard_Boolean IsEqual (const Iterator& theOther) const
124 return myVector == theOther.myVector
125 && myCurIndex == theOther.myCurIndex
126 && myEndIndex == theOther.myEndIndex
127 && myICurBlock == theOther.myICurBlock
128 && myIEndBlock == theOther.myIEndBlock;
132 //! Shorthand for a regular iterator type.
133 typedef NCollection_StlIterator<std::random_access_iterator_tag, Iterator, TheItemType, false> iterator;
135 //! Shorthand for a constant iterator type.
136 typedef NCollection_StlIterator<std::random_access_iterator_tag, Iterator, TheItemType, true> const_iterator;
138 //! Returns an iterator pointing to the first element in the vector.
139 iterator begin() const { return Iterator (*this, false); }
141 //! Returns an iterator referring to the past-the-end element in the vector.
142 iterator end() const { return Iterator (*this, true); }
144 //! Returns a const iterator pointing to the first element in the vector.
145 const_iterator cbegin() const { return Iterator (*this, false); }
147 //! Returns a const iterator referring to the past-the-end element in the vector.
148 const_iterator cend() const { return Iterator (*this, true); }
150 public: //! @name public methods
153 explicit NCollection_Vector (const Standard_Integer theIncrement = 256,
154 const Handle(NCollection_BaseAllocator)& theAlloc = NULL) :
155 NCollection_BaseVector (theAlloc, initMemBlocks, sizeof(TheItemType), theIncrement)
159 NCollection_Vector (const NCollection_Vector& theOther) :
160 NCollection_BaseVector (theOther.myAllocator, initMemBlocks, theOther)
166 virtual ~NCollection_Vector()
168 for (Standard_Integer anItemIter = 0; anItemIter < myCapacity; ++anItemIter)
170 initMemBlocks (*this, myData[anItemIter], 0, 0);
172 this->myAllocator->Free (myData);
175 //! Total number of items
176 Standard_Integer Length() const
181 //! Total number of items in the vector
182 Standard_Integer Size() const
187 //! Method for consistency with other collections.
188 //! @return Lower bound (inclusive) for iteration.
189 Standard_Integer Lower() const
194 //! Method for consistency with other collections.
195 //! @return Upper bound (inclusive) for iteration.
196 Standard_Integer Upper() const
202 Standard_Boolean IsEmpty() const
204 return (myLength == 0);
207 //! Assignment to the collection of the same type
208 inline void Assign (const NCollection_Vector& theOther,
209 const Standard_Boolean theOwnAllocator = Standard_True);
211 //! Assignment operator
212 NCollection_Vector& operator= (const NCollection_Vector& theOther)
214 Assign (theOther, Standard_False);
219 TheItemType& Append (const TheItemType& theValue)
221 TheItemType& anAppended = *(TheItemType* )expandV (myLength);
222 anAppended = theValue;
226 //! Appends an empty value and returns the reference to it
227 TheItemType& Appended ()
229 TheItemType& anAppended = *(TheItemType* )expandV (myLength);
233 //! Operator() - query the const value
234 const TheItemType& operator() (const Standard_Integer theIndex) const
236 return Value (theIndex);
239 //! Operator[] - query the const value
240 const TheItemType& operator[] (Standard_Integer theIndex) const { return Value (theIndex); }
242 const TheItemType& Value (const Standard_Integer theIndex) const
244 return *(const TheItemType* )findV (theIndex);
247 //! @return first element
248 const TheItemType& First() const
250 return *(const TheItemType* )findV (Lower());
253 //! @return first element
254 TheItemType& ChangeFirst()
256 return *(TheItemType* )findV (Lower());
259 //! @return last element
260 const TheItemType& Last() const
262 return *(const TheItemType* )findV (Upper());
265 //! @return last element
266 TheItemType& ChangeLast()
268 return *(TheItemType* )findV (Upper());
271 //! Operator() - query the value
272 TheItemType& operator() (const Standard_Integer theIndex)
274 return ChangeValue (theIndex);
277 //! Operator[] - query the value
278 TheItemType& operator[] ( Standard_Integer theIndex) { return ChangeValue (theIndex); }
280 TheItemType& ChangeValue (const Standard_Integer theIndex)
282 return *(TheItemType* )findV (theIndex);
285 //! SetValue () - set or append a value
286 TheItemType& SetValue (const Standard_Integer theIndex,
287 const TheItemType& theValue)
289 Standard_OutOfRange_Raise_if (theIndex < 0, "NCollection_Vector::SetValue");
290 TheItemType* const aVecValue = (TheItemType* )(theIndex < myLength ? findV (theIndex) : expandV (theIndex));
291 *aVecValue = theValue;
295 private: //! @name private methods
297 void copyData (const NCollection_Vector& theOther)
299 Standard_Integer iBlock = 0;
300 /*NCollection_Vector::*/Iterator anIter (theOther);
301 for (Standard_Integer aLength = 0; aLength < myLength; aLength += myIncrement)
303 MemBlock& aBlock = myData[iBlock];
304 initMemBlocks (*this, aBlock, aLength, myIncrement);
305 Standard_Integer anItemIter = 0;
306 for (; anItemIter < myIncrement; ++anItemIter)
313 ((TheItemType* )aBlock.DataPtr)[anItemIter] = anIter.Value();
316 aBlock.Length = anItemIter;
321 //! Method to initialize memory block content
322 static void initMemBlocks (NCollection_BaseVector& theVector,
323 NCollection_BaseVector::MemBlock& theBlock,
324 const Standard_Integer theFirst,
325 const Standard_Integer theSize)
327 NCollection_Vector& aSelf = static_cast<NCollection_Vector&> (theVector);
328 Handle(NCollection_BaseAllocator)& anAllocator = aSelf.myAllocator;
330 // release current content
331 if (theBlock.DataPtr != NULL)
333 for (Standard_Integer anItemIter = 0; anItemIter < theBlock.Size; ++anItemIter)
335 ((TheItemType* )theBlock.DataPtr)[anItemIter].~TheItemType();
337 anAllocator->Free (theBlock.DataPtr);
338 theBlock.DataPtr = NULL;
341 // allocate new content if requested
344 theBlock.DataPtr = anAllocator->Allocate (theSize * sizeof(TheItemType));
345 for (Standard_Integer anItemIter = 0; anItemIter < theSize; ++anItemIter)
347 new (&((TheItemType* )theBlock.DataPtr)[anItemIter]) TheItemType;
350 theBlock.FirstIndex = theFirst;
351 theBlock.Size = theSize;
355 friend class Iterator;
359 //! Assignment to the collection of the same type
360 template <class TheItemType> inline
361 void NCollection_Vector<TheItemType>::Assign (const NCollection_Vector& theOther,
362 const Standard_Boolean theOwnAllocator)
364 if (this == &theOther)
369 // destroy current data using current allocator
370 for (Standard_Integer anItemIter = 0; anItemIter < myCapacity; ++anItemIter)
372 initMemBlocks (*this, myData[anItemIter], 0, 0);
374 this->myAllocator->Free (myData);
376 // allocate memory blocks with new allocator
377 if (!theOwnAllocator)
379 this->myAllocator = theOther.myAllocator;
381 myIncrement = theOther.myIncrement;
382 myLength = theOther.myLength;
383 myNBlocks = (myLength == 0) ? 0 : (1 + (myLength - 1)/myIncrement);
384 myCapacity = GetCapacity (myIncrement) + myLength / myIncrement;
385 myData = allocMemBlocks (myCapacity);
391 #endif // NCollection_Vector_HeaderFile