0024831: Make iterators of NCollection classes STL-compatible
[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 #ifndef No_Exception
20 #include <Standard_DimensionMismatch.hxx>
21 #include <Standard_OutOfMemory.hxx>
22 #include <Standard_OutOfRange.hxx>
23 #endif
24
25 #include <NCollection_BaseCollection.hxx>
26 #include <NCollection_StlIterator.hxx>
27
28 // *********************************************** Template for Array1 class
29
30 /**
31 * Purpose:     The class Array1 represents unidimensional arrays 
32 *              of fixed size known at run time. 
33 *              The range of the index is user defined.
34 *              An array1 can be constructed with a "C array".
35 *              This functionality is useful to call methods expecting
36 *              an Array1. It allows to carry the bounds inside the arrays.
37 *              
38 * Examples:    Item tab[100]; //  An example with a C array
39 *              Array1OfItem ttab (tab[0],1,100);
40 *              
41 *              Array1OfItem tttab (ttab(10),10,20); // a slice of ttab
42 *              
43 *              If you want to reindex an array from 1 to Length do :
44 *              
45 *              Array1 tab1(tab(tab.Lower()),1,tab.Length());
46 *                          
47 * Warning:     Programs client of such a class must be independant
48 *              of the range of the first element. Then, a C++ for
49 *              loop must be written like this
50 *              
51 *              for (i = A.Lower(); i <= A.Upper(); i++)
52 *              
53 * Changes:     In  comparison  to  TCollection  the  flag  isAllocated  was
54 *              renamed into myDeletable (alike in  the Array2).  For naming
55 *              compatibility the method IsAllocated remained in class along
56 *              with IsDeletable.
57 */              
58 template <class TheItemType> class NCollection_Array1
59   : public NCollection_BaseCollection<TheItemType>
60 {
61 public:
62   //! STL-compliant typedef for value type
63   typedef TheItemType value_type;
64
65 public:
66   //! Implementation of the Iterator interface.
67   class Iterator : public NCollection_BaseCollection<TheItemType>::Iterator
68   {
69   public:
70
71     //! Empty constructor - for later Init
72     Iterator (void) :
73       myPtrCur (NULL),
74       myPtrEnd (NULL)
75     {
76       //
77     }
78
79     //! Constructor with initialization
80     Iterator (const NCollection_Array1& theArray, Standard_Boolean theToEnd = Standard_False) :
81       myPtrEnd (const_cast<TheItemType*> (&theArray.Last() + 1))
82     {
83       myPtrCur = theToEnd ? myPtrEnd : const_cast<TheItemType*> (&theArray.First());
84     }
85
86     //! Initialisation
87     void Init (const NCollection_Array1& theArray)
88     { 
89       myPtrCur = const_cast<TheItemType*> (&theArray.First());
90       myPtrEnd = const_cast<TheItemType*> (&theArray.Last() + 1);
91     }
92
93     //! Assignment
94     Iterator& operator= (const Iterator& theOther)
95     {
96       myPtrCur = theOther.myPtrCur;
97       myPtrEnd = theOther.myPtrEnd;
98       return *this;
99     }
100
101     //! Check end
102     virtual Standard_Boolean More (void) const
103     { return myPtrCur < myPtrEnd; }
104     
105     //! Increment operator
106     virtual void Next (void)
107     { ++myPtrCur; }
108
109     //! Decrement operator
110     virtual void Previous()
111     { --myPtrCur; }
112
113     //! Offset operator.
114     virtual void Offset (ptrdiff_t theOffset)
115     { myPtrCur += theOffset; }
116
117     //! Difference operator.
118     virtual ptrdiff_t Differ (const Iterator& theOther) const
119     { return myPtrCur - theOther.myPtrCur; }
120
121     //! Constant value access
122     virtual const TheItemType& Value (void) const
123     { return *myPtrCur; }
124
125     //! Variable value access
126     virtual TheItemType& ChangeValue (void) const 
127     { return *myPtrCur; }
128
129     //! Performs comparison of two iterators
130     virtual Standard_Boolean IsEqual (const Iterator& theOther) const
131     { return myPtrCur == theOther.myPtrCur; }
132
133   private:
134     TheItemType* myPtrCur; //!< Pointer to the current element in the array
135     TheItemType* myPtrEnd; //!< Pointer to the past-the-end element in the array
136   }; // End of the nested class Iterator
137
138   //! Shorthand for a regular iterator type.
139   typedef NCollection_StlIterator<std::random_access_iterator_tag, Iterator, TheItemType, false> iterator;
140
141   //! Shorthand for a constant iterator type.
142   typedef NCollection_StlIterator<std::random_access_iterator_tag, Iterator, TheItemType, true> const_iterator;
143
144   //! Returns an iterator pointing to the first element in the array.
145   iterator begin() const { return Iterator (*this, false); }
146
147   //! Returns an iterator referring to the past-the-end element in the array.
148   iterator end() const { return Iterator (*this, true); }
149   
150   //! Returns a const iterator pointing to the first element in the array.
151   const_iterator cbegin() const { return Iterator (*this, false); }
152
153   //! Returns a const iterator referring to the past-the-end element in the array.
154   const_iterator cend() const { return Iterator (*this, true); }
155
156  public:
157   // ---------- PUBLIC METHODS ------------
158
159   //! Constructor
160   NCollection_Array1(const Standard_Integer theLower,
161                      const Standard_Integer theUpper) :
162                 NCollection_BaseCollection<TheItemType>  (),
163                 myLowerBound                             (theLower),
164                 myUpperBound                             (theUpper),
165                 myDeletable                              (Standard_True)
166   {
167 #if !defined No_Exception && !defined No_Standard_RangeError
168     if (theUpper < theLower)
169       Standard_RangeError::Raise ("NCollection_Array1::Create");
170 #endif
171     TheItemType* pBegin = new TheItemType[Length()];
172 #if !defined No_Exception && !defined No_Standard_OutOfMemory
173     if (!pBegin)
174       Standard_OutOfMemory::Raise ("NCollection_Array1 : Allocation failed");
175 #endif
176
177     myData = pBegin - theLower;
178   }
179
180   //! Copy constructor 
181   NCollection_Array1 (const NCollection_Array1& theOther) :
182     NCollection_BaseCollection<TheItemType>     (),
183     myLowerBound                                (theOther.Lower()),
184     myUpperBound                                (theOther.Upper()),
185     myDeletable                                 (Standard_True)
186   {
187     TheItemType* pBegin = new TheItemType[Length()];
188 #if !defined No_Exception && !defined No_Standard_OutOfMemory
189     if (!pBegin)
190       Standard_OutOfMemory::Raise ("NCollection_Array1 : Allocation failed");
191 #endif
192     myData = pBegin - myLowerBound;
193
194     *this = theOther;
195   }
196
197   //! C array-based constructor
198   NCollection_Array1 (const TheItemType& theBegin,
199                       const Standard_Integer theLower,
200                       const Standard_Integer theUpper) :
201     NCollection_BaseCollection<TheItemType>     (),
202     myLowerBound                                (theLower),
203     myUpperBound                                (theUpper),
204     myDeletable                                 (Standard_False)
205   {
206 #if !defined No_Exception && !defined No_Standard_RangeError
207     if (theUpper < theLower)
208       Standard_RangeError::Raise ("NCollection_Array1::Array1");
209 #endif
210     myData = (TheItemType *) &theBegin - theLower; 
211   }
212
213   //! Initialise the items with theValue
214   void Init (const TheItemType& theValue) 
215   {
216     TheItemType *pCur = &myData[myLowerBound], *pEnd=&myData[myUpperBound];
217     for(; pCur <= pEnd; pCur++)
218       *pCur = (TheItemType&) theValue;
219   }
220
221   //! Size query
222   virtual Standard_Integer Size (void) const
223   { return Length(); }
224   //! Length query (the same)
225   Standard_Integer Length (void) const
226   { return (myUpperBound-myLowerBound+1); }
227
228   //! Lower bound
229   Standard_Integer Lower (void) const
230   { return myLowerBound; }
231   //! Upper bound
232   Standard_Integer Upper (void) const
233   { return myUpperBound; }
234
235   //! myDeletable flag
236   Standard_Boolean IsDeletable (void) const
237   { return myDeletable; }
238
239   //! IsAllocated flag - for naming compatibility
240   Standard_Boolean IsAllocated (void) const
241   { return myDeletable; }
242
243   //! Assign (any collection to this array)
244   // Copies items from the other collection into the allocated
245   // storage. Raises an exception when sizes differ.
246   virtual void Assign (const NCollection_BaseCollection<TheItemType>& theOther)
247   {
248     if (&theOther == this)
249       return;
250 #if !defined No_Exception && !defined No_Standard_DimensionMismatch
251     if (Length() != theOther.Size())
252       Standard_DimensionMismatch::Raise ("NCollection_Array1::Assign");
253 #endif
254     TYPENAME NCollection_BaseCollection<TheItemType>::Iterator& anIter2 = 
255       theOther.CreateIterator();
256     TheItemType * const pEndItem = &myData[myUpperBound];
257     for (TheItemType * pItem = &myData[myLowerBound];
258          pItem <= pEndItem;   anIter2.Next())
259       * pItem ++ = anIter2.Value();
260   }
261
262   //! operator= (array to array)
263   NCollection_Array1& operator= (const NCollection_Array1& theOther)
264   {
265     if (&theOther == this)
266       return *this;
267 #if !defined No_Exception && !defined No_Standard_DimensionMismatch
268     if (Length() != theOther.Length())
269       Standard_DimensionMismatch::Raise ("NCollection_Array1::operator=");
270 #endif
271     TheItemType * pMyItem        = &myData[myLowerBound];
272     TheItemType * const pEndItem = &(theOther.myData)[theOther.myUpperBound];
273     TheItemType * pItem          = &(theOther.myData)[theOther.myLowerBound];
274     while (pItem <= pEndItem) * pMyItem ++ = * pItem ++;
275     return *this; 
276   }
277
278   //! @return first element
279   const TheItemType& First() const
280   {
281     return myData[myLowerBound];
282   }
283
284   //! @return first element
285   TheItemType& ChangeFirst()
286   {
287     return myData[myLowerBound];
288   }
289
290   //! @return last element
291   const TheItemType& Last() const
292   {
293     return myData[myUpperBound];
294   }
295
296   //! @return last element
297   TheItemType& ChangeLast()
298   {
299     return myData[myUpperBound];
300   }
301
302   //! Constant value access
303   const TheItemType& Value (const Standard_Integer theIndex) const
304   {
305 #if !defined No_Exception && !defined No_Standard_OutOfRange
306     if (theIndex < myLowerBound || theIndex > myUpperBound)
307       Standard_OutOfRange::Raise ("NCollection_Array1::Value");
308 #endif
309     return myData[theIndex];
310   }
311
312   //! operator() - alias to Value
313   const TheItemType& operator() (const Standard_Integer theIndex) const
314   { return Value (theIndex); }
315
316   //! Variable value access
317   TheItemType& ChangeValue (const Standard_Integer theIndex)
318   {
319 #if !defined No_Exception && !defined No_Standard_OutOfRange
320     if (theIndex < myLowerBound || theIndex > myUpperBound)
321       Standard_OutOfRange::Raise ("NCollection_Array1::ChangeValue");
322 #endif
323     return myData[theIndex];
324   }
325
326   //! operator() - alias to ChangeValue
327   TheItemType& operator() (const Standard_Integer theIndex)
328   { return ChangeValue (theIndex); }
329
330   //! Set value 
331   void SetValue (const Standard_Integer theIndex,
332                  const TheItemType&     theItem)
333   {
334 #if !defined No_Exception && !defined No_Standard_OutOfRange
335     if (theIndex < myLowerBound || theIndex > myUpperBound)
336       Standard_OutOfRange::Raise ("NCollection_Array1::SetValue");
337 #endif
338     myData[theIndex] = theItem;
339   }
340
341   //! Destructor - releases the memory
342   ~NCollection_Array1 (void)
343   { if (myDeletable) delete [] &(myData[myLowerBound]); }
344
345  private:
346   // ----------- PRIVATE METHODS -----------
347
348   // ******** Creates Iterator for use on BaseCollection
349   virtual
350   TYPENAME NCollection_BaseCollection<TheItemType>::Iterator& 
351                         CreateIterator(void) const
352   { return *(new (this->IterAllocator()) Iterator(*this)); }
353
354  protected:
355   // ---------- PROTECTED FIELDS -----------
356   Standard_Integer     myLowerBound;
357   Standard_Integer     myUpperBound;
358   Standard_Boolean     myDeletable; //!< Flag showing who allocated the array
359   TheItemType*         myData;      //!< Pointer to '0'th array item
360 };
361
362 #endif