0022048: Visualization, AIS_InteractiveContext - single object selection should alway...
[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   NCollection_Array1 (NCollection_Array1&& theOther)
196   : myLowerBound (theOther.myLowerBound),
197     myUpperBound (theOther.myUpperBound),
198     myDeletable  (theOther.myDeletable),
199     myData       (theOther.myData)
200   {
201     theOther.myUpperBound = theOther.myLowerBound - 1;
202     theOther.myDeletable  = false;
203     theOther.myData       = NULL;
204   }
205
206   //! C array-based constructor
207   NCollection_Array1 (const TheItemType& theBegin,
208                       const Standard_Integer theLower,
209                       const Standard_Integer theUpper) :
210     myLowerBound                                (theLower),
211     myUpperBound                                (theUpper),
212     myDeletable                                 (Standard_False)
213   {
214     Standard_RangeError_Raise_if (theUpper < theLower, "NCollection_Array1::Create");
215   #if (defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
216     // gcc emits -Warray-bounds warning when NCollection_Array1 is initialized
217     // from local array with lower index 1 (so that (&theBegin - 1) points out of array bounds).
218     // NCollection_Array1 initializes myData with a shift to avoid this shift within per-element access.
219     // It is undesired changing this logic, and -Warray-bounds is not useful here.
220     #pragma GCC diagnostic push
221     #pragma GCC diagnostic ignored "-Warray-bounds"
222   #endif
223     myData = (TheItemType *) &theBegin - theLower;
224   #if (defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
225     #pragma GCC diagnostic pop
226   #endif
227   }
228
229   //! Initialise the items with theValue
230   void Init (const TheItemType& theValue) 
231   {
232     TheItemType *pCur = &myData[myLowerBound], *pEnd=&myData[myUpperBound];
233     for(; pCur <= pEnd; pCur++)
234       *pCur = (TheItemType&) theValue;
235   }
236
237   //! Size query
238   Standard_Integer Size (void) const
239   { return Length(); }
240   //! Length query (the same)
241   Standard_Integer Length (void) const
242   { return (myUpperBound-myLowerBound+1); }
243
244   //! Return TRUE if array has zero length.
245   Standard_Boolean IsEmpty() const { return myUpperBound < myLowerBound; }
246
247   //! Lower bound
248   Standard_Integer Lower (void) const
249   { return myLowerBound; }
250   //! Upper bound
251   Standard_Integer Upper (void) const
252   { return myUpperBound; }
253
254   //! myDeletable flag
255   Standard_Boolean IsDeletable (void) const
256   { return myDeletable; }
257
258   //! IsAllocated flag - for naming compatibility
259   Standard_Boolean IsAllocated (void) const
260   { return myDeletable; }
261
262   //! Assignment
263   NCollection_Array1& Assign (const NCollection_Array1& theOther)
264   {
265     if (&theOther == this)
266       return *this;
267
268     Standard_DimensionMismatch_Raise_if (Length() != theOther.Length(), "NCollection_Array1::operator=");
269     if (myData == NULL)
270     {
271       return *this;
272     }
273
274     TheItemType * pMyItem        = &myData[myLowerBound];
275     TheItemType * const pEndItem = &(theOther.myData)[theOther.myUpperBound];
276     TheItemType * pItem          = &(theOther.myData)[theOther.myLowerBound];
277     while (pItem <= pEndItem) * pMyItem ++ = * pItem ++;
278     return *this;
279   }
280
281   //! Move assignment
282   NCollection_Array1& Move (NCollection_Array1&& theOther)
283   {
284     if (&theOther == this)
285     {
286       return *this;
287     }
288
289     if (myDeletable)
290     {
291       delete[] &myData[myLowerBound];
292     }
293     myLowerBound = theOther.myLowerBound;
294     myUpperBound = theOther.myUpperBound;
295     myDeletable  = theOther.myDeletable;
296     myData       = theOther.myData;
297
298     theOther.myUpperBound = theOther.myLowerBound - 1;
299     theOther.myDeletable  = Standard_False;
300     theOther.myData       = NULL;
301     return *this;
302   }
303
304   //! Assignment operator
305   NCollection_Array1& operator= (const NCollection_Array1& theOther)
306   { 
307     return Assign (theOther);
308   }
309
310   //! Move assignment operator.
311   NCollection_Array1& operator= (NCollection_Array1&& theOther)
312   {
313     return Move (std::move (theOther));
314   }
315
316   //! @return first element
317   const TheItemType& First() const
318   {
319     return myData[myLowerBound];
320   }
321
322   //! @return first element
323   TheItemType& ChangeFirst()
324   {
325     return myData[myLowerBound];
326   }
327
328   //! @return last element
329   const TheItemType& Last() const
330   {
331     return myData[myUpperBound];
332   }
333
334   //! @return last element
335   TheItemType& ChangeLast()
336   {
337     return myData[myUpperBound];
338   }
339
340   //! Constant value access
341   const TheItemType& Value (const Standard_Integer theIndex) const
342   {
343     Standard_OutOfRange_Raise_if (theIndex < myLowerBound || theIndex > myUpperBound, "NCollection_Array1::Value");
344     return myData[theIndex];
345   }
346
347   //! operator() - alias to Value
348   const TheItemType& operator() (const Standard_Integer theIndex) const
349   { return Value (theIndex); }
350
351   //! Variable value access
352   TheItemType& ChangeValue (const Standard_Integer theIndex)
353   {
354     Standard_OutOfRange_Raise_if (theIndex < myLowerBound || theIndex > myUpperBound, "NCollection_Array1::ChangeValue");
355     return myData[theIndex];
356   }
357
358   //! operator() - alias to ChangeValue
359   TheItemType& operator() (const Standard_Integer theIndex)
360   { return ChangeValue (theIndex); }
361
362   //! Set value 
363   void SetValue (const Standard_Integer theIndex,
364                  const TheItemType&     theItem)
365   {
366     Standard_OutOfRange_Raise_if (theIndex < myLowerBound || theIndex > myUpperBound, "NCollection_Array1::SetValue");
367     myData[theIndex] = theItem;
368   }
369
370   //! Resizes the array to specified bounds.
371   //! No re-allocation will be done if length of array does not change,
372   //! but existing values will not be discarded if theToCopyData set to FALSE.
373   //! @param theLower new lower bound of array
374   //! @param theUpper new upper bound of array
375   //! @param theToCopyData flag to copy existing data into new array
376   void Resize (const Standard_Integer theLower,
377                const Standard_Integer theUpper,
378                const Standard_Boolean theToCopyData)
379   {
380     Standard_RangeError_Raise_if (theUpper < theLower, "NCollection_Array1::Resize");
381     const Standard_Integer anOldLen   = Length();
382     const Standard_Integer aNewLen    = theUpper - theLower + 1;
383     const Standard_Integer aLowerOld  = myLowerBound;
384
385     TheItemType* aBeginOld = &myData[aLowerOld];
386     myLowerBound = theLower;
387     myUpperBound = theUpper;
388     if (aNewLen == anOldLen)
389     {
390       myData = aBeginOld - theLower;
391       return;
392     }
393
394     if (!theToCopyData && myDeletable)
395     {
396       delete[] aBeginOld;
397     }
398     TheItemType* aBeginNew = new TheItemType[aNewLen];
399     Standard_OutOfMemory_Raise_if (aBeginNew == NULL, "NCollection_Array1 : Allocation failed");
400     myData = aBeginNew - theLower;
401     if (!theToCopyData)
402     {
403       myDeletable = Standard_True;
404       return;
405     }
406
407     const Standard_Integer aLenCopy = Min (anOldLen, aNewLen);
408     for (Standard_Integer anIter = 0; anIter < aLenCopy; ++anIter)
409     {
410       aBeginNew[anIter] = aBeginOld[anIter];
411     }
412     if (myDeletable)
413     {
414       delete[] aBeginOld;
415     }
416     myDeletable = Standard_True;
417   }
418
419   //! Destructor - releases the memory
420   ~NCollection_Array1 (void)
421   { if (myDeletable) delete [] &(myData[myLowerBound]); }
422
423  protected:
424   // ---------- PROTECTED FIELDS -----------
425   Standard_Integer     myLowerBound;
426   Standard_Integer     myUpperBound;
427   Standard_Boolean     myDeletable; //!< Flag showing who allocated the array
428   TheItemType*         myData;      //!< Pointer to '0'th array item
429 };
430
431 #endif