85d2c43affd70f317e9173b547cda9f7032ca0ca
[occt.git] / src / NCollection / NCollection_Array1.hxx
1 // Created on: 2002-04-15
2 // Created by: Alexander Kartomin (akm)
3 // Copyright (c) 2002-2014 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_Array1_HeaderFile
17 #define NCollection_Array1_HeaderFile
18
19 #include <Standard_DimensionMismatch.hxx>
20 #include <Standard_OutOfMemory.hxx>
21 #include <Standard_OutOfRange.hxx>
22
23 #include <NCollection_DefineAlloc.hxx>
24 #include <NCollection_StlIterator.hxx>
25
26 // *********************************************** Template for Array1 class
27
28 /**
29 * Purpose:     The class Array1 represents unidimensional arrays 
30 *              of fixed size known at run time. 
31 *              The range of the index is user defined.
32 *              An array1 can be constructed with a "C array".
33 *              This functionality is useful to call methods expecting
34 *              an Array1. It allows to carry the bounds inside the arrays.
35 *              
36 * Examples:    Item tab[100]; //  An example with a C array
37 *              Array1OfItem ttab (tab[0],1,100);
38 *              
39 *              Array1OfItem tttab (ttab(10),10,20); // a slice of ttab
40 *              
41 *              If you want to reindex an array from 1 to Length do :
42 *              
43 *              Array1 tab1(tab(tab.Lower()),1,tab.Length());
44 *                          
45 * Warning:     Programs client of such a class must be independant
46 *              of the range of the first element. Then, a C++ for
47 *              loop must be written like this
48 *              
49 *              for (i = A.Lower(); i <= A.Upper(); i++)
50 *              
51 * Changes:     In  comparison  to  TCollection  the  flag  isAllocated  was
52 *              renamed into myDeletable (alike in  the Array2).  For naming
53 *              compatibility the method IsAllocated remained in class along
54 *              with IsDeletable.
55 */              
56 template <class TheItemType>
57 class NCollection_Array1
58 {
59 public:
60   //! STL-compliant typedef for value type
61   typedef TheItemType value_type;
62
63 public:
64   //! Implementation of the Iterator interface.
65   class Iterator
66   {
67   public:
68
69     //! Empty constructor - for later Init
70     Iterator (void) :
71       myPtrCur (NULL),
72       myPtrEnd (NULL)
73     {
74       //
75     }
76
77     //! Constructor with initialization
78     Iterator (const NCollection_Array1& theArray, Standard_Boolean theToEnd = Standard_False) :
79       myPtrEnd (const_cast<TheItemType*> (&theArray.Last() + 1))
80     {
81       myPtrCur = theToEnd ? myPtrEnd : const_cast<TheItemType*> (&theArray.First());
82     }
83
84     //! Initialisation
85     void Init (const NCollection_Array1& theArray)
86     { 
87       myPtrCur = const_cast<TheItemType*> (&theArray.First());
88       myPtrEnd = const_cast<TheItemType*> (&theArray.Last() + 1);
89     }
90
91     //! Assignment
92     Iterator& operator= (const Iterator& theOther)
93     {
94       myPtrCur = theOther.myPtrCur;
95       myPtrEnd = theOther.myPtrEnd;
96       return *this;
97     }
98
99     //! Check end
100     Standard_Boolean More (void) const
101     { return myPtrCur < myPtrEnd; }
102     
103     //! Increment operator
104     void Next (void)
105     { ++myPtrCur; }
106
107     //! Decrement operator
108     void Previous()
109     { --myPtrCur; }
110
111     //! Offset operator.
112     void Offset (ptrdiff_t theOffset)
113     { myPtrCur += theOffset; }
114
115     //! Difference operator.
116     ptrdiff_t Differ (const Iterator& theOther) const
117     { return myPtrCur - theOther.myPtrCur; }
118
119     //! Constant value access
120     const TheItemType& Value (void) const
121     { return *myPtrCur; }
122
123     //! Variable value access
124     TheItemType& ChangeValue (void) const 
125     { return *myPtrCur; }
126
127     //! Performs comparison of two iterators
128     Standard_Boolean IsEqual (const Iterator& theOther) const
129     { return myPtrCur == theOther.myPtrCur; }
130
131   private:
132     TheItemType* myPtrCur; //!< Pointer to the current element in the array
133     TheItemType* myPtrEnd; //!< Pointer to the past-the-end element in the array
134   }; // End of the nested class Iterator
135
136   //! Shorthand for a regular iterator type.
137   typedef NCollection_StlIterator<std::random_access_iterator_tag, Iterator, TheItemType, false> iterator;
138
139   //! Shorthand for a constant iterator type.
140   typedef NCollection_StlIterator<std::random_access_iterator_tag, Iterator, TheItemType, true> const_iterator;
141
142   //! Returns an iterator pointing to the first element in the array.
143   iterator begin() const { return Iterator (*this, false); }
144
145   //! Returns an iterator referring to the past-the-end element in the array.
146   iterator end() const { return Iterator (*this, true); }
147   
148   //! Returns a const iterator pointing to the first element in the array.
149   const_iterator cbegin() const { return Iterator (*this, false); }
150
151   //! Returns a const iterator referring to the past-the-end element in the array.
152   const_iterator cend() const { return Iterator (*this, true); }
153
154  public:
155   // ---------- PUBLIC METHODS ------------
156
157   //! Empty constructor; should be used with caution.
158   NCollection_Array1()
159   : myLowerBound (1),
160     myUpperBound (0),
161     myDeletable  (Standard_False),
162     myData (NULL)
163   {
164     //
165   }
166
167   //! Constructor
168   NCollection_Array1(const Standard_Integer theLower,
169                      const Standard_Integer theUpper) :
170                 myLowerBound                             (theLower),
171                 myUpperBound                             (theUpper),
172                 myDeletable                              (Standard_True)
173   {
174     Standard_RangeError_Raise_if (theUpper < theLower, "NCollection_Array1::Create");
175     TheItemType* pBegin = new TheItemType[Length()];
176     Standard_OutOfMemory_Raise_if (!pBegin, "NCollection_Array1 : Allocation failed");
177
178     myData = pBegin - theLower;
179   }
180
181   //! Copy constructor 
182   NCollection_Array1 (const NCollection_Array1& theOther) :
183     myLowerBound                                (theOther.Lower()),
184     myUpperBound                                (theOther.Upper()),
185     myDeletable                                 (Standard_True)
186   {
187     TheItemType* pBegin = new TheItemType[Length()];
188     Standard_OutOfMemory_Raise_if (!pBegin, "NCollection_Array1 : Allocation failed");
189     myData = pBegin - myLowerBound;
190
191     *this = theOther;
192   }
193
194   //! Move constructor
195 #if(defined(_MSC_VER) && (_MSC_VER < 1600))
196 #else
197   NCollection_Array1 (NCollection_Array1&& theOther)
198   : myLowerBound (theOther.myLowerBound),
199     myUpperBound (theOther.myUpperBound),
200     myDeletable  (theOther.myDeletable),
201     myData       (theOther.myData)
202   {
203     theOther.myUpperBound = theOther.myLowerBound - 1;
204     theOther.myDeletable  = false;
205     theOther.myData       = NULL;
206   }
207 #endif
208
209   //! C array-based constructor
210   NCollection_Array1 (const TheItemType& theBegin,
211                       const Standard_Integer theLower,
212                       const Standard_Integer theUpper) :
213     myLowerBound                                (theLower),
214     myUpperBound                                (theUpper),
215     myDeletable                                 (Standard_False)
216   {
217     Standard_RangeError_Raise_if (theUpper < theLower, "NCollection_Array1::Create");
218   #if (defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
219     // gcc emits -Warray-bounds warning when NCollection_Array1 is initialized
220     // from local array with lower index 1 (so that (&theBegin - 1) points out of array bounds).
221     // NCollection_Array1 initializes myData with a shift to avoid this shift within per-element access.
222     // It is undesired changing this logic, and -Warray-bounds is not useful here.
223     #pragma GCC diagnostic push
224     #pragma GCC diagnostic ignored "-Warray-bounds"
225   #endif
226     myData = (TheItemType *) &theBegin - theLower;
227   #if (defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
228     #pragma GCC diagnostic pop
229   #endif
230   }
231
232   //! Initialise the items with theValue
233   void Init (const TheItemType& theValue) 
234   {
235     TheItemType *pCur = &myData[myLowerBound], *pEnd=&myData[myUpperBound];
236     for(; pCur <= pEnd; pCur++)
237       *pCur = (TheItemType&) theValue;
238   }
239
240   //! Size query
241   Standard_Integer Size (void) const
242   { return Length(); }
243   //! Length query (the same)
244   Standard_Integer Length (void) const
245   { return (myUpperBound-myLowerBound+1); }
246
247   //! Return TRUE if array has zero length.
248   Standard_Boolean IsEmpty() const { return myUpperBound < myLowerBound; }
249
250   //! Lower bound
251   Standard_Integer Lower (void) const
252   { return myLowerBound; }
253   //! Upper bound
254   Standard_Integer Upper (void) const
255   { return myUpperBound; }
256
257   //! myDeletable flag
258   Standard_Boolean IsDeletable (void) const
259   { return myDeletable; }
260
261   //! IsAllocated flag - for naming compatibility
262   Standard_Boolean IsAllocated (void) const
263   { return myDeletable; }
264
265   //! Assignment
266   NCollection_Array1& Assign (const NCollection_Array1& theOther)
267   {
268     if (&theOther == this)
269       return *this;
270
271     Standard_DimensionMismatch_Raise_if (Length() != theOther.Length(), "NCollection_Array1::operator=");
272     if (myData == NULL)
273     {
274       return *this;
275     }
276
277     TheItemType * pMyItem        = &myData[myLowerBound];
278     TheItemType * const pEndItem = &(theOther.myData)[theOther.myUpperBound];
279     TheItemType * pItem          = &(theOther.myData)[theOther.myLowerBound];
280     while (pItem <= pEndItem) * pMyItem ++ = * pItem ++;
281     return *this;
282   }
283
284   //! Move assignment
285   NCollection_Array1& Move (NCollection_Array1& theOther)
286   {
287     if (&theOther == this)
288     {
289       return *this;
290     }
291
292     if (myDeletable)
293     {
294       delete[] &myData[myLowerBound];
295     }
296     myLowerBound = theOther.myLowerBound;
297     myUpperBound = theOther.myUpperBound;
298     myDeletable  = theOther.myDeletable;
299     myData       = theOther.myData;
300
301     theOther.myUpperBound = theOther.myLowerBound - 1;
302     theOther.myDeletable  = Standard_False;
303     theOther.myData       = NULL;
304     return *this;
305   }
306
307   //! Assignment operator
308   NCollection_Array1& operator= (const NCollection_Array1& theOther)
309   { 
310     return Assign (theOther);
311   }
312
313   //! Move assignment operator.
314 #if(defined(_MSC_VER) && (_MSC_VER < 1600))
315 #else
316   NCollection_Array1& operator= (NCollection_Array1&& theOther)
317   {
318     return Move (theOther);
319   }
320 #endif
321
322   //! @return first element
323   const TheItemType& First() const
324   {
325     return myData[myLowerBound];
326   }
327
328   //! @return first element
329   TheItemType& ChangeFirst()
330   {
331     return myData[myLowerBound];
332   }
333
334   //! @return last element
335   const TheItemType& Last() const
336   {
337     return myData[myUpperBound];
338   }
339
340   //! @return last element
341   TheItemType& ChangeLast()
342   {
343     return myData[myUpperBound];
344   }
345
346   //! Constant value access
347   const TheItemType& Value (const Standard_Integer theIndex) const
348   {
349     Standard_OutOfRange_Raise_if (theIndex < myLowerBound || theIndex > myUpperBound, "NCollection_Array1::Value");
350     return myData[theIndex];
351   }
352
353   //! operator() - alias to Value
354   const TheItemType& operator() (const Standard_Integer theIndex) const
355   { return Value (theIndex); }
356
357   //! Variable value access
358   TheItemType& ChangeValue (const Standard_Integer theIndex)
359   {
360     Standard_OutOfRange_Raise_if (theIndex < myLowerBound || theIndex > myUpperBound, "NCollection_Array1::ChangeValue");
361     return myData[theIndex];
362   }
363
364   //! operator() - alias to ChangeValue
365   TheItemType& operator() (const Standard_Integer theIndex)
366   { return ChangeValue (theIndex); }
367
368   //! Set value 
369   void SetValue (const Standard_Integer theIndex,
370                  const TheItemType&     theItem)
371   {
372     Standard_OutOfRange_Raise_if (theIndex < myLowerBound || theIndex > myUpperBound, "NCollection_Array1::SetValue");
373     myData[theIndex] = theItem;
374   }
375
376   //! Resizes the array to specified bounds.
377   //! No re-allocation will be done if length of array does not change,
378   //! but existing values will not be discarded if theToCopyData set to FALSE.
379   //! @param theLower new lower bound of array
380   //! @param theUpper new upper bound of array
381   //! @param theToCopyData flag to copy existing data into new array
382   void Resize (const Standard_Integer theLower,
383                const Standard_Integer theUpper,
384                const Standard_Boolean theToCopyData)
385   {
386     Standard_RangeError_Raise_if (theUpper < theLower, "NCollection_Array1::Resize");
387     const Standard_Integer anOldLen   = Length();
388     const Standard_Integer aNewLen    = theUpper - theLower + 1;
389     const Standard_Integer aLowerOld  = myLowerBound;
390
391     TheItemType* aBeginOld = &myData[aLowerOld];
392     myLowerBound = theLower;
393     myUpperBound = theUpper;
394     if (aNewLen == anOldLen)
395     {
396       myData = aBeginOld - theLower;
397       return;
398     }
399
400     if (!theToCopyData && myDeletable)
401     {
402       delete[] aBeginOld;
403     }
404     TheItemType* aBeginNew = new TheItemType[aNewLen];
405     Standard_OutOfMemory_Raise_if (aBeginNew == NULL, "NCollection_Array1 : Allocation failed");
406     myData = aBeginNew - theLower;
407     if (!theToCopyData)
408     {
409       myDeletable = Standard_True;
410       return;
411     }
412
413     const Standard_Integer aLenCopy = Min (anOldLen, aNewLen);
414     for (Standard_Integer anIter = 0; anIter < aLenCopy; ++anIter)
415     {
416       aBeginNew[anIter] = aBeginOld[anIter];
417     }
418     if (myDeletable)
419     {
420       delete[] aBeginOld;
421     }
422     myDeletable = Standard_True;
423   }
424
425   //! Destructor - releases the memory
426   ~NCollection_Array1 (void)
427   { if (myDeletable) delete [] &(myData[myLowerBound]); }
428
429  protected:
430   // ---------- PROTECTED FIELDS -----------
431   Standard_Integer     myLowerBound;
432   Standard_Integer     myUpperBound;
433   Standard_Boolean     myDeletable; //!< Flag showing who allocated the array
434   TheItemType*         myData;      //!< Pointer to '0'th array item
435 };
436
437 #endif