7594290ac030013cfe59051fd7bf49cde83ce7b5
[occt.git] / src / NCollection / NCollection_Vector.hxx
1 // Created on: 2002-04-23
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2002-2013 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #ifndef NCollection_Vector_HeaderFile
17 #define NCollection_Vector_HeaderFile
18
19 #include <NCollection_BaseVector.hxx>
20 #include <NCollection_StlIterator.hxx>
21
22 //! Class NCollection_Vector (dynamic array of objects)
23 //!
24 //! This class is similar to NCollection_Array1  though the indices always start
25 //! at 0 (in Array1 the first index must be specified)
26 //!
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-
32 //!     date this index
33 //!
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.
38 //!
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
45 {
46 public:
47   //! STL-compliant typedef for value type
48   typedef TheItemType value_type;
49
50 public:
51
52   //! Nested class Iterator
53   class Iterator : public NCollection_BaseVector::Iterator
54   {
55   public:
56
57     //! Empty constructor - for later Init
58     Iterator() {}
59
60     //! Constructor with initialisation
61     Iterator (const NCollection_Vector& theVector, Standard_Boolean theToEnd = Standard_False)
62     : NCollection_BaseVector::Iterator (theVector, theToEnd) {}
63
64     //! Copy constructor
65     Iterator (const Iterator& theOther)
66     : NCollection_BaseVector::Iterator (theOther) {}
67
68     //! Initialisation
69     void Init (const NCollection_Vector& theVector)
70     {
71       initV (theVector);
72     }
73
74     //! Assignment
75     Iterator& operator= (const Iterator& theOther)
76     {
77       copyV (theOther);
78       return *this;
79     }
80
81     //! Check end
82     Standard_Boolean More() const
83     {
84       return moreV();
85     }
86
87     //! Increment operator.
88     void Next()
89     {
90       nextV();
91     }
92
93     //! Decrement operator.
94     void Previous()
95     {
96       prevV();
97     }
98
99     //! Offset operator.
100     void Offset (ptrdiff_t theOffset)
101     {
102       offsetV (static_cast<int>(theOffset));
103     }
104
105     //! Difference operator.
106     ptrdiff_t Differ (const Iterator& theOther) const
107     {
108       return differV (theOther);
109     }
110
111     //! Constant value access
112     const TheItemType& Value() const
113     {
114       return ((const TheItemType* )curBlockV()->DataPtr)[myCurIndex];
115     }
116
117     //! Variable value access
118     TheItemType& ChangeValue() const
119     {
120       return ((TheItemType* )curBlockV()->DataPtr)[myCurIndex];
121     }
122
123     //! Performs comparison of two iterators.
124     Standard_Boolean IsEqual (const Iterator& theOther) const
125     {
126       return myVector    == theOther.myVector
127           && myCurIndex  == theOther.myCurIndex
128           && myEndIndex  == theOther.myEndIndex  
129           && myICurBlock == theOther.myICurBlock
130           && myIEndBlock == theOther.myIEndBlock;
131     }
132   };
133
134   //! Shorthand for a regular iterator type.
135   typedef NCollection_StlIterator<std::random_access_iterator_tag, Iterator, TheItemType, false> iterator;
136
137   //! Shorthand for a constant iterator type.
138   typedef NCollection_StlIterator<std::random_access_iterator_tag, Iterator, TheItemType, true> const_iterator;
139
140   //! Returns an iterator pointing to the first element in the vector.
141   iterator begin() const { return Iterator (*this, false); }
142
143   //! Returns an iterator referring to the past-the-end element in the vector.
144   iterator end() const { return Iterator (*this, true); }
145
146   //! Returns a const iterator pointing to the first element in the vector.
147   const_iterator cbegin() const { return Iterator (*this, false); }
148
149   //! Returns a const iterator referring to the past-the-end element in the vector.
150   const_iterator cend() const { return Iterator (*this, true); }
151
152 public: //! @name public methods
153
154   //! Constructor
155   explicit NCollection_Vector (const Standard_Integer theIncrement              = 256,
156                                const Handle(NCollection_BaseAllocator)& theAlloc = NULL) :
157     NCollection_BaseVector (theAlloc, initMemBlocks, sizeof(TheItemType), theIncrement)
158   {}
159
160   //! Copy constructor
161   NCollection_Vector (const NCollection_Vector& theOther) :
162     NCollection_BaseVector (theOther.myAllocator, initMemBlocks, theOther)
163   {
164     copyData (theOther);
165   }
166
167   //! Destructor
168   virtual ~NCollection_Vector()
169   {
170     for (Standard_Integer anItemIter = 0; anItemIter < myCapacity; ++anItemIter)
171     {
172       initMemBlocks (*this, myData[anItemIter], 0, 0);
173     }
174     this->myAllocator->Free (myData);
175   }
176
177   //! Total number of items
178   Standard_Integer Length() const
179   {
180     return myLength;
181   }
182
183   //! Total number of items in the vector
184   Standard_Integer Size() const
185   {
186     return myLength;
187   }
188
189   //! Method for consistency with other collections.
190   //! @return Lower bound (inclusive) for iteration.
191   Standard_Integer Lower() const
192   {
193     return 0;
194   }
195
196   //! Method for consistency with other collections.
197   //! @return Upper bound (inclusive) for iteration.
198   Standard_Integer Upper() const
199   {
200     return myLength - 1;
201   }
202
203   //! Empty query
204   Standard_Boolean IsEmpty() const
205   {
206     return (myLength == 0);
207   }
208
209   //! Assignment to the collection of the same type
210   inline void Assign (const NCollection_Vector& theOther,
211                       const Standard_Boolean theOwnAllocator = Standard_True);
212
213   //! Assignment operator
214   NCollection_Vector& operator= (const NCollection_Vector& theOther)
215   {
216     Assign (theOther, Standard_False);
217     return *this;
218   }
219
220   //! Append
221   TheItemType& Append (const TheItemType& theValue)
222   {
223     TheItemType& anAppended = *(TheItemType* )expandV (myLength);
224     anAppended = theValue;
225     return anAppended;
226   }
227
228   //! Appends an empty value and returns the reference to it
229   TheItemType& Appended ()
230   {
231     TheItemType& anAppended = *(TheItemType* )expandV (myLength);
232     return anAppended;
233   }
234
235   //! Operator() - query the const value
236   const TheItemType& operator() (const Standard_Integer theIndex) const
237   {
238     return Value (theIndex);
239   }
240
241   //! Operator[] - query the const value
242   const TheItemType& operator[] (Standard_Integer theIndex) const { return Value (theIndex); }
243
244   const TheItemType& Value (const Standard_Integer theIndex) const
245   {
246     return *(const TheItemType* )findV (theIndex);
247   }
248
249   //! @return first element
250   const TheItemType& First() const
251   {
252     return *(const TheItemType* )findV (Lower());
253   }
254
255   //! @return first element
256   TheItemType& ChangeFirst()
257   {
258     return *(TheItemType* )findV (Lower());
259   }
260
261   //! @return last element
262   const TheItemType& Last() const
263   {
264     return *(const TheItemType* )findV (Upper());
265   }
266
267   //! @return last element
268   TheItemType& ChangeLast()
269   {
270     return *(TheItemType* )findV (Upper());
271   }
272
273   //! Operator() - query the value
274   TheItemType& operator() (const Standard_Integer theIndex)
275   {
276     return ChangeValue (theIndex);
277   }
278
279   //! Operator[] - query the value
280   TheItemType& operator[] ( Standard_Integer theIndex) { return ChangeValue (theIndex); }
281
282   TheItemType& ChangeValue (const Standard_Integer theIndex)
283   {
284     return *(TheItemType* )findV (theIndex);
285   }
286
287   //! SetValue () - set or append a value
288   TheItemType& SetValue (const Standard_Integer theIndex,
289                          const TheItemType&     theValue)
290   {
291     Standard_OutOfRange_Raise_if (theIndex < 0, "NCollection_Vector::SetValue");
292     TheItemType* const aVecValue = (TheItemType* )(theIndex < myLength ? findV (theIndex) : expandV (theIndex));
293     *aVecValue = theValue;
294     return *aVecValue;
295   }
296
297 private: //! @name private methods
298
299   void copyData (const NCollection_Vector& theOther)
300   {
301     Standard_Integer iBlock = 0;
302     /*NCollection_Vector::*/Iterator anIter (theOther);
303     for (Standard_Integer aLength = 0; aLength < myLength; aLength += myIncrement)
304     {
305       MemBlock& aBlock = myData[iBlock];
306       initMemBlocks (*this, aBlock, aLength, myIncrement);
307       Standard_Integer anItemIter = 0;
308       for (; anItemIter < myIncrement; ++anItemIter)
309       {
310         if (!anIter.More())
311         {
312           break;
313         }
314
315         ((TheItemType* )aBlock.DataPtr)[anItemIter] = anIter.Value();
316         anIter.Next();
317       }
318       aBlock.Length = anItemIter;
319       iBlock++;
320     }
321   }
322
323   //! Method to initialize memory block content
324   static void initMemBlocks (NCollection_BaseVector&           theVector,
325                              NCollection_BaseVector::MemBlock& theBlock,
326                              const Standard_Integer            theFirst,
327                              const Standard_Integer            theSize)
328   {
329     NCollection_Vector& aSelf = static_cast<NCollection_Vector&> (theVector);
330     Handle(NCollection_BaseAllocator)& anAllocator = aSelf.myAllocator;
331
332     // release current content
333     if (theBlock.DataPtr != NULL)
334     {
335       for (Standard_Integer anItemIter = 0; anItemIter < theBlock.Size; ++anItemIter)
336       {
337         ((TheItemType* )theBlock.DataPtr)[anItemIter].~TheItemType();
338       }
339       anAllocator->Free (theBlock.DataPtr);
340       theBlock.DataPtr = NULL;
341     }
342
343     // allocate new content if requested
344     if (theSize > 0)
345     {
346       theBlock.DataPtr = anAllocator->Allocate (theSize * sizeof(TheItemType));
347       for (Standard_Integer anItemIter = 0; anItemIter < theSize; ++anItemIter)
348       {
349         new (&((TheItemType* )theBlock.DataPtr)[anItemIter]) TheItemType;
350       }
351     }
352     theBlock.FirstIndex = theFirst;
353     theBlock.Size       = theSize;
354     theBlock.Length     = 0;
355   }
356
357   friend class Iterator;
358
359 };
360
361 //! Assignment to the collection of the same type
362 template <class TheItemType> inline
363 void NCollection_Vector<TheItemType>::Assign (const NCollection_Vector& theOther,
364                                               const Standard_Boolean    theOwnAllocator)
365 {
366   if (this == &theOther)
367   {
368     return;
369   }
370
371   // destroy current data using current allocator
372   for (Standard_Integer anItemIter = 0; anItemIter < myCapacity; ++anItemIter)
373   {
374     initMemBlocks (*this, myData[anItemIter], 0, 0);
375   }
376   this->myAllocator->Free (myData);
377
378   // allocate memory blocks with new allocator
379   if (!theOwnAllocator)
380   {
381     this->myAllocator = theOther.myAllocator;
382   }
383   myIncrement = theOther.myIncrement;
384   myLength    = theOther.myLength;
385   myNBlocks   = (myLength == 0) ? 0 : (1 + (myLength - 1)/myIncrement);
386   myCapacity  = GetCapacity (myIncrement) + myLength / myIncrement;
387   myData      = allocMemBlocks (myCapacity);
388
389   // copy data
390   copyData (theOther);
391 }
392
393 #endif // NCollection_Vector_HeaderFile