1 // Created on: 2002-04-15
2 // Created by: Alexander Kartomin (akm)
3 // Copyright (c) 2002-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #ifndef NCollection_Array1_HeaderFile
17 #define NCollection_Array1_HeaderFile
19 #include <Standard_DimensionMismatch.hxx>
20 #include <Standard_OutOfMemory.hxx>
21 #include <Standard_OutOfRange.hxx>
23 #include <NCollection_DefineAlloc.hxx>
24 #include <NCollection_StlIterator.hxx>
26 // *********************************************** Template for Array1 class
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.
36 * Examples: Item tab[100]; // An example with a C array
37 * Array1OfItem ttab (tab[0],1,100);
39 * Array1OfItem tttab (ttab(10),10,20); // a slice of ttab
41 * If you want to reindex an array from 1 to Length do :
43 * Array1 tab1(tab(tab.Lower()),1,tab.Length());
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
49 * for (i = A.Lower(); i <= A.Upper(); i++)
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
56 template <class TheItemType>
57 class NCollection_Array1
60 //! STL-compliant typedef for value type
61 typedef TheItemType value_type;
64 //! Implementation of the Iterator interface.
69 //! Empty constructor - for later Init
77 //! Constructor with initialization
78 Iterator (const NCollection_Array1& theArray, Standard_Boolean theToEnd = Standard_False) :
79 myPtrEnd (const_cast<TheItemType*> (&theArray.Last() + 1))
81 myPtrCur = theToEnd ? myPtrEnd : const_cast<TheItemType*> (&theArray.First());
85 void Init (const NCollection_Array1& theArray)
87 myPtrCur = const_cast<TheItemType*> (&theArray.First());
88 myPtrEnd = const_cast<TheItemType*> (&theArray.Last() + 1);
92 Standard_Boolean More (void) const
93 { return myPtrCur < myPtrEnd; }
95 //! Increment operator
99 //! Decrement operator
104 void Offset (ptrdiff_t theOffset)
105 { myPtrCur += theOffset; }
107 //! Difference operator.
108 ptrdiff_t Differ (const Iterator& theOther) const
109 { return myPtrCur - theOther.myPtrCur; }
111 //! Constant value access
112 const TheItemType& Value (void) const
113 { return *myPtrCur; }
115 //! Variable value access
116 TheItemType& ChangeValue (void) const
117 { return *myPtrCur; }
119 //! Performs comparison of two iterators
120 Standard_Boolean IsEqual (const Iterator& theOther) const
121 { return myPtrCur == theOther.myPtrCur; }
124 TheItemType* myPtrCur; //!< Pointer to the current element in the array
125 TheItemType* myPtrEnd; //!< Pointer to the past-the-end element in the array
126 }; // End of the nested class Iterator
128 //! Shorthand for a regular iterator type.
129 typedef NCollection_StlIterator<std::random_access_iterator_tag, Iterator, TheItemType, false> iterator;
131 //! Shorthand for a constant iterator type.
132 typedef NCollection_StlIterator<std::random_access_iterator_tag, Iterator, TheItemType, true> const_iterator;
134 //! Returns an iterator pointing to the first element in the array.
135 iterator begin() const { return Iterator (*this, false); }
137 //! Returns an iterator referring to the past-the-end element in the array.
138 iterator end() const { return Iterator (*this, true); }
140 //! Returns a const iterator pointing to the first element in the array.
141 const_iterator cbegin() const { return Iterator (*this, false); }
143 //! Returns a const iterator referring to the past-the-end element in the array.
144 const_iterator cend() const { return Iterator (*this, true); }
147 // ---------- PUBLIC METHODS ------------
149 //! Empty constructor; should be used with caution.
150 //! @sa methods Resize() and Move().
154 myDeletable (Standard_False),
161 NCollection_Array1(const Standard_Integer theLower,
162 const Standard_Integer theUpper) :
163 myLowerBound (theLower),
164 myUpperBound (theUpper),
165 myDeletable (Standard_True)
167 Standard_RangeError_Raise_if (theUpper < theLower, "NCollection_Array1::Create");
168 TheItemType* pBegin = new TheItemType[Length()];
169 Standard_OutOfMemory_Raise_if (!pBegin, "NCollection_Array1 : Allocation failed");
171 myData = pBegin - theLower;
175 NCollection_Array1 (const NCollection_Array1& theOther) :
176 myLowerBound (theOther.Lower()),
177 myUpperBound (theOther.Upper()),
178 myDeletable (Standard_True)
180 TheItemType* pBegin = new TheItemType[Length()];
181 Standard_OutOfMemory_Raise_if (!pBegin, "NCollection_Array1 : Allocation failed");
182 myData = pBegin - myLowerBound;
187 #ifndef OCCT_NO_RVALUE_REFERENCE
189 NCollection_Array1 (NCollection_Array1&& theOther)
190 : myLowerBound (theOther.myLowerBound),
191 myUpperBound (theOther.myUpperBound),
192 myDeletable (theOther.myDeletable),
193 myData (theOther.myData)
195 theOther.myDeletable = false;
199 //! C array-based constructor.
201 //! Makes this array to use the buffer pointed by theBegin
202 //! instead of allocating it dynamically.
203 //! Argument theBegin should be a reference to the first element
204 //! of the pre-allocated buffer (usually local C array buffer),
205 //! with size at least theUpper - theLower + 1 items.
207 //! Warning: returning array object created using this constructor
208 //! from function by value will result in undefined behavior
209 //! if compiler performs return value optimization (this is likely
210 //! to be true for all modern compilers in release mode).
211 //! The same happens if array is copied using Move() function
212 //! or move constructor and target object's lifespan is longer
213 //! than that of the buffer.
214 NCollection_Array1 (const TheItemType& theBegin,
215 const Standard_Integer theLower,
216 const Standard_Integer theUpper) :
217 myLowerBound (theLower),
218 myUpperBound (theUpper),
219 myDeletable (Standard_False)
221 Standard_RangeError_Raise_if (theUpper < theLower, "NCollection_Array1::Create");
222 #if (defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
223 // gcc emits -Warray-bounds warning when NCollection_Array1 is initialized
224 // from local array with lower index 1 (so that (&theBegin - 1) points out of array bounds).
225 // NCollection_Array1 initializes myData with a shift to avoid this shift within per-element access.
226 // It is undesired changing this logic, and -Warray-bounds is not useful here.
227 #pragma GCC diagnostic push
228 #pragma GCC diagnostic ignored "-Warray-bounds"
230 myData = (TheItemType *) &theBegin - theLower;
231 #if (defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
232 #pragma GCC diagnostic pop
236 //! Initialise the items with theValue
237 void Init (const TheItemType& theValue)
239 TheItemType *pCur = &myData[myLowerBound], *pEnd=&myData[myUpperBound];
240 for(; pCur <= pEnd; pCur++)
241 *pCur = (TheItemType&) theValue;
245 Standard_Integer Size (void) const
247 //! Length query (the same)
248 Standard_Integer Length (void) const
249 { return (myUpperBound-myLowerBound+1); }
251 //! Return TRUE if array has zero length.
252 Standard_Boolean IsEmpty() const { return myUpperBound < myLowerBound; }
255 Standard_Integer Lower (void) const
256 { return myLowerBound; }
258 Standard_Integer Upper (void) const
259 { return myUpperBound; }
262 Standard_Boolean IsDeletable (void) const
263 { return myDeletable; }
265 //! IsAllocated flag - for naming compatibility
266 Standard_Boolean IsAllocated (void) const
267 { return myDeletable; }
269 //! Copies data of theOther array to this.
270 //! This array should be pre-allocated and have the same length as theOther;
271 //! otherwise exception Standard_DimensionMismatch is thrown.
272 NCollection_Array1& Assign (const NCollection_Array1& theOther)
274 if (&theOther == this)
277 Standard_DimensionMismatch_Raise_if (Length() != theOther.Length(), "NCollection_Array1::operator=");
283 TheItemType * pMyItem = &myData[myLowerBound];
284 TheItemType * const pEndItem = &(theOther.myData)[theOther.myUpperBound];
285 TheItemType * pItem = &(theOther.myData)[theOther.myLowerBound];
286 while (pItem <= pEndItem) * pMyItem ++ = * pItem ++;
291 //! This array will borrow all the data from theOther.
292 //! The moved object will keep pointer to the memory buffer and
293 //! range, but it will not free the buffer on destruction.
294 NCollection_Array1& Move (NCollection_Array1& theOther)
296 if (&theOther == this)
303 delete[] &myData[myLowerBound];
306 myLowerBound = theOther.myLowerBound;
307 myUpperBound = theOther.myUpperBound;
308 myDeletable = theOther.myDeletable;
309 myData = theOther.myData;
311 theOther.myDeletable = Standard_False;
316 //! Assignment operator; @sa Assign()
317 NCollection_Array1& operator= (const NCollection_Array1& theOther)
319 return Assign (theOther);
322 #ifndef OCCT_NO_RVALUE_REFERENCE
323 //! Move assignment operator; @sa Move()
324 NCollection_Array1& operator= (NCollection_Array1&& theOther)
326 return Move (theOther);
330 //! @return first element
331 const TheItemType& First() const
333 return myData[myLowerBound];
336 //! @return first element
337 TheItemType& ChangeFirst()
339 return myData[myLowerBound];
342 //! @return last element
343 const TheItemType& Last() const
345 return myData[myUpperBound];
348 //! @return last element
349 TheItemType& ChangeLast()
351 return myData[myUpperBound];
354 //! Constant value access
355 const TheItemType& Value (const Standard_Integer theIndex) const
357 Standard_OutOfRange_Raise_if (theIndex < myLowerBound || theIndex > myUpperBound, "NCollection_Array1::Value");
358 return myData[theIndex];
361 //! operator() - alias to Value
362 const TheItemType& operator() (const Standard_Integer theIndex) const
363 { return Value (theIndex); }
365 //! operator[] - alias to Value
366 const TheItemType& operator[] (Standard_Integer theIndex) const { return Value (theIndex); }
368 //! Variable value access
369 TheItemType& ChangeValue (const Standard_Integer theIndex)
371 Standard_OutOfRange_Raise_if (theIndex < myLowerBound || theIndex > myUpperBound, "NCollection_Array1::ChangeValue");
372 return myData[theIndex];
375 //! operator() - alias to ChangeValue
376 TheItemType& operator() (const Standard_Integer theIndex)
377 { return ChangeValue (theIndex); }
379 //! operator[] - alias to ChangeValue
380 TheItemType& operator[] (Standard_Integer theIndex) { return ChangeValue (theIndex); }
383 void SetValue (const Standard_Integer theIndex,
384 const TheItemType& theItem)
386 Standard_OutOfRange_Raise_if (theIndex < myLowerBound || theIndex > myUpperBound, "NCollection_Array1::SetValue");
387 myData[theIndex] = theItem;
390 //! Resizes the array to specified bounds.
391 //! No re-allocation will be done if length of array does not change,
392 //! but existing values will not be discarded if theToCopyData set to FALSE.
393 //! @param theLower new lower bound of array
394 //! @param theUpper new upper bound of array
395 //! @param theToCopyData flag to copy existing data into new array
396 void Resize (const Standard_Integer theLower,
397 const Standard_Integer theUpper,
398 const Standard_Boolean theToCopyData)
400 Standard_RangeError_Raise_if (theUpper < theLower, "NCollection_Array1::Resize");
401 const Standard_Integer anOldLen = Length();
402 const Standard_Integer aNewLen = theUpper - theLower + 1;
403 const Standard_Integer aLowerOld = myLowerBound;
405 TheItemType* aBeginOld = &myData[aLowerOld];
406 myLowerBound = theLower;
407 myUpperBound = theUpper;
408 if (aNewLen == anOldLen)
410 myData = aBeginOld - theLower;
414 if (!theToCopyData && myDeletable)
418 TheItemType* aBeginNew = new TheItemType[aNewLen];
419 Standard_OutOfMemory_Raise_if (aBeginNew == NULL, "NCollection_Array1 : Allocation failed");
420 myData = aBeginNew - theLower;
423 myDeletable = Standard_True;
427 const Standard_Integer aLenCopy = Min (anOldLen, aNewLen);
428 for (Standard_Integer anIter = 0; anIter < aLenCopy; ++anIter)
430 aBeginNew[anIter] = aBeginOld[anIter];
436 myDeletable = Standard_True;
439 //! Destructor - releases the memory
440 ~NCollection_Array1 (void)
443 delete [] &(myData[myLowerBound]);
447 // ---------- PROTECTED FIELDS -----------
448 Standard_Integer myLowerBound;
449 Standard_Integer myUpperBound;
450 Standard_Boolean myDeletable; //!< Flag showing who allocated the array
451 TheItemType* myData; //!< Pointer to '0'th array item