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