0023284: Using 'memcpy' on class that contains a virtual method
[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 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
9 //
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 //
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
19
20 #ifndef NCollection_Vector_HeaderFile
21 #define NCollection_Vector_HeaderFile
22
23 #include <NCollection_BaseVector.hxx>
24 #include <NCollection_BaseCollection.hxx>
25
26 //! Class NCollection_Vector (dynamic array of objects)
27 //!
28 //! This class is similar to NCollection_Array1  though the indices always start
29 //! at 0 (in Array1 the first index must be specified)
30 //!
31 //! The Vector is always created with 0 length. It can be enlarged by two means:
32 //!  1. Calling the method Append (val) - then "val" is added to the end of the
33 //!     vector (the vector length is incremented)
34 //!  2. Calling the method SetValue (i, val)  - if "i" is greater than or equal
35 //!     to the current length of the vector,  the vector is enlarged to accomo-
36 //!     date this index
37 //!
38 //! The methods Append and SetValue return  a non-const reference  to the copied
39 //! object  inside  the vector.  This reference  is guaranteed to be valid until
40 //! the vector is destroyed. It can be used to access the vector member directly
41 //! or to pass its address to other data structures.
42 //!
43 //! The vector iterator remembers the length of the vector  at the moment of the
44 //! creation or initialisation of the iterator.   Therefore the iteration begins
45 //! at index 0  and stops at the index equal to (remembered_length-1).  It is OK
46 //! to enlarge the vector during the iteration.
47 template <class TheItemType> class NCollection_Vector
48 : public NCollection_BaseCollection<TheItemType>,
49   public NCollection_BaseVector
50 {
51 public:
52
53   typedef TheItemType TheItemTypeD;
54
55   //! Nested class Iterator
56   class Iterator : public NCollection_BaseCollection<TheItemType>::Iterator,
57                    public NCollection_BaseVector::Iterator
58   {
59   public:
60
61     //! Empty constructor - for later Init
62     Iterator() {}
63
64     //! Constructor with initialisation
65     Iterator (const NCollection_Vector& theVector)
66     : NCollection_BaseVector::Iterator (theVector) {}
67
68     //! Copy constructor
69     Iterator (const Iterator& theOther)
70     : NCollection_BaseVector::Iterator (theOther) {}
71
72     //! Initialisation
73     void Init (const NCollection_Vector& theVector)
74     {
75       initV (theVector);
76     }
77
78     //! Assignment
79     Iterator& operator= (const Iterator& theOther)
80     {
81       copyV (theOther);
82       return *this;
83     }
84
85     //! Check end
86     virtual Standard_Boolean More() const
87     {
88       return moreV();
89     }
90
91     //! Make step
92     virtual void Next()
93     {
94       nextV();
95     }
96
97     //! Constant value access
98     virtual const TheItemType& Value() const
99     {
100       return ((const TheItemType* )curBlockV()->DataPtr)[myCurIndex];
101     }
102
103     //! Variable value access
104     virtual TheItemType& ChangeValue() const
105     {
106       return ((TheItemType* )curBlockV()->DataPtr)[myCurIndex];
107     }
108
109   };
110
111 public: //! @name public methods
112
113   //! Constructor
114   NCollection_Vector (const Standard_Integer theIncrement              = 256,
115                       const Handle_NCollection_BaseAllocator& theAlloc = NULL)
116   : NCollection_BaseCollection<TheItemType> (theAlloc),
117     NCollection_BaseVector (NCollection_BaseCollection<TheItemType>::myAllocator, initMemBlocks, sizeof(TheItemType), theIncrement) {}
118
119   //! Copy constructor
120   NCollection_Vector (const NCollection_Vector& theOther)
121   : NCollection_BaseCollection<TheItemType> (theOther.myAllocator),
122     NCollection_BaseVector (NCollection_BaseCollection<TheItemType>::myAllocator, initMemBlocks, theOther)
123   {
124     copyData (theOther);
125   }
126
127   //! Destructor
128   ~NCollection_Vector()
129   {
130     for (Standard_Integer anItemIter = 0; anItemIter < myCapacity; ++anItemIter)
131     {
132       initMemBlocks (*this, myData[anItemIter], 0, 0);
133     }
134     NCollection_BaseCollection<TheItemType>::myAllocator->Free (myData);
135   }
136
137   //! Operator=
138   NCollection_Vector& operator= (const NCollection_Vector& theOther)
139   {
140     Assign (theOther, Standard_False);
141     return *this;
142   }
143
144   //! Total number of items
145   Standard_Integer Length() const
146   {
147     return myLength;
148   }
149
150   //! Total number of items in the vector
151   virtual Standard_Integer Size() const
152   {
153     return myLength;
154   }
155
156   //! Method for consistency with other collections.
157   //! @return Lower bound (inclusive) for iteration.
158   Standard_Integer Lower() const
159   {
160     return 0;
161   }
162
163   //! Method for consistency with other collections.
164   //! @return Upper bound (inclusive) for iteration.
165   Standard_Integer Upper() const
166   {
167     return myLength - 1;
168   }
169
170   //! Empty query
171   Standard_Boolean IsEmpty() const
172   {
173     return (myLength == 0);
174   }
175
176   //! Virtual assignment (any collection to this array)
177   virtual void Assign (const NCollection_BaseCollection<TheItemType>& theOther)
178   {
179     if (this != &theOther)
180     {
181       TYPENAME NCollection_BaseCollection<TheItemType>::Iterator& anIter2 = theOther.CreateIterator();
182       while (anIter2.More())
183       {
184         Append (anIter2.Value());
185         anIter2.Next();
186       }
187     }
188   }
189
190   //! Assignment to the collection of the same type
191   inline void Assign (const NCollection_Vector& theOther,
192                       const Standard_Boolean    theOwnAllocator = Standard_True);
193
194   //! Method to create iterators for base collections
195   virtual TYPENAME NCollection_BaseCollection<TheItemType>::Iterator& CreateIterator() const
196   {
197     return *(new (this->IterAllocator()) Iterator(*this));
198   }
199
200   //! Append
201   TheItemType& Append (const TheItemType& theValue)
202   {
203     TheItemType& anAppended = *(TheItemType* )expandV (NCollection_BaseCollection<TheItemType>::myAllocator, myLength);
204     anAppended = theValue;
205     return anAppended;
206   }
207
208   //! Operator() - query the const value
209   const TheItemType& operator() (const Standard_Integer theIndex) const
210   {
211     return Value (theIndex);
212   }
213
214   const TheItemType& Value (const Standard_Integer theIndex) const
215   {
216     return *(const TheItemType* )findV (theIndex);
217   }
218
219   //! @return first element
220   const TheItemType& First() const
221   {
222     return *(const TheItemType* )findV (Lower());
223   }
224
225   //! @return first element
226   TheItemType& ChangeFirst()
227   {
228     return *(TheItemType* )findV (Lower());
229   }
230
231   //! @return last element
232   const TheItemType& Last() const
233   {
234     return *(const TheItemType* )findV (Upper());
235   }
236
237   //! @return last element
238   TheItemType& ChangeLast()
239   {
240     return *(TheItemType* )findV (Upper());
241   }
242
243   //! Operator() - query the value
244   TheItemType& operator() (const Standard_Integer theIndex)
245   {
246     return ChangeValue (theIndex);
247   }
248
249   TheItemType& ChangeValue (const Standard_Integer theIndex)
250   {
251     return *(TheItemType* )findV (theIndex);
252   }
253
254   //! SetValue () - set or append a value
255   TheItemType& SetValue (const Standard_Integer theIndex,
256                          const TheItemType&     theValue)
257   {
258     Standard_OutOfRange_Raise_if (theIndex < 0, "NCollection_Vector::SetValue");
259     TheItemType* const aVecValue = (TheItemType* )(theIndex < myLength ? findV (theIndex) : expandV (NCollection_BaseCollection<TheItemType>::myAllocator, theIndex));
260     *aVecValue = theValue;
261     return *aVecValue;
262   }
263
264 private: //! @name private methods
265
266   void copyData (const NCollection_Vector& theOther)
267   {
268     Standard_Integer iBlock = 0;
269     /*NCollection_Vector::*/Iterator anIter (theOther);
270     for (Standard_Integer aLength = 0; aLength < myLength; aLength += myIncrement)
271     {
272       MemBlock& aBlock = myData[iBlock];
273       initMemBlocks (*this, aBlock, aLength, myIncrement);
274       Standard_Integer anItemIter = 0;
275       for (; anItemIter < myIncrement; ++anItemIter)
276       {
277         if (!anIter.More())
278         {
279           break;
280         }
281
282         ((TheItemType* )aBlock.DataPtr)[anItemIter] = anIter.Value();
283         anIter.Next();
284       }
285       aBlock.Length = anItemIter;
286       iBlock++;
287     }
288   }
289
290   //! Method to initialize memory block content
291   static void initMemBlocks (NCollection_BaseVector&           theVector,
292                              NCollection_BaseVector::MemBlock& theBlock,
293                              const Standard_Integer            theFirst,
294                              const Standard_Integer            theSize)
295   {
296     NCollection_Vector& aSelf = static_cast<NCollection_Vector&> (theVector);
297     Handle(NCollection_BaseAllocator)& anAllocator = aSelf.myAllocator;
298
299     // release current content
300     if (theBlock.DataPtr != NULL)
301     {
302       for (Standard_Integer anItemIter = 0; anItemIter < theBlock.Size; ++anItemIter)
303       {
304         ((TheItemType* )theBlock.DataPtr)[anItemIter].~TheItemTypeD();
305       }
306       anAllocator->Free (theBlock.DataPtr);
307       theBlock.DataPtr = NULL;
308     }
309
310     // allocate new content if requested
311     if (theSize > 0)
312     {
313       theBlock.DataPtr = anAllocator->Allocate (theSize * sizeof(TheItemType));
314       for (Standard_Integer anItemIter = 0; anItemIter < theSize; ++anItemIter)
315       {
316         new (&((TheItemType* )theBlock.DataPtr)[anItemIter]) TheItemType;
317       }
318     }
319     theBlock.FirstIndex = theFirst;
320     theBlock.Size       = theSize;
321     theBlock.Length     = 0;
322   }
323
324   friend class Iterator;
325
326 };
327
328 //! Assignment to the collection of the same type
329 template <class TheItemType> inline
330 void NCollection_Vector<TheItemType>::Assign (const NCollection_Vector& theOther,
331                                               const Standard_Boolean    theOwnAllocator)
332 {
333   if (this == &theOther)
334   {
335     return;
336   }
337
338   // destroy current data using current allocator
339   for (Standard_Integer anItemIter = 0; anItemIter < myCapacity; ++anItemIter)
340   {
341     initMemBlocks (*this, myData[anItemIter], 0, 0);
342   }
343   NCollection_BaseCollection<TheItemType>::myAllocator->Free (myData);
344
345   // allocate memory blocks with new allocator
346   if (!theOwnAllocator)
347   {
348     NCollection_BaseCollection<TheItemType>::myAllocator = theOther.myAllocator;
349   }
350   myIncrement = theOther.myIncrement;
351   myLength    = theOther.myLength;
352   myNBlocks   = (myLength == 0) ? 0 : (1 + (myLength - 1)/myIncrement);
353   myCapacity  = GetCapacity (myIncrement) + myLength / myIncrement;
354   myData      = allocMemBlocks (NCollection_BaseCollection<TheItemType>::myAllocator, myCapacity);
355
356   // copy data
357   copyData (theOther);
358 }
359
360 #endif // NCollection_Vector_HeaderFile