Step size region by region.
[u/mrichter/AliRoot.git] / CONTAINERS / AliMemArray.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 ///////////////////////////////////////////////////////////////////////////////
19 //                                                                           //
20 //  AliMemArray                                                              //                      
21 //  (Pseudo)Container optimised for fast  random access operator[ ]. 
22 //  Operator []  time doesn’t depend on the number of elements in container O(1) - 
23 //    like in standard array or like in STL vector
24 //   To achieve maximally-fast indexing and iteration in one buffer mode  
25 //   the vector maintains its storage as a single contiguous array of objects (one buffer mode)
26
27 //   When a vector runs out of pre-allocated storage, in order to maintain it 
28 //   contiguous array it must allocate a whole new (larger) chunk of storage  
29 //   elsewhere and copy the objects to the new storage.
30 //       void *  AliMemArray::Unchecked1DAt(UInt_t i) const                    
31 //             return  &(((char*)fCont)[fObjectSize*i]);
32
33 //   In multi buffer mode (like two dimensional array) when a vector runs out of 
34 //   pre-allocated storage we don’t need to copy whole array only small buffer but operator [] is slower
35 //       void *  AliMemArray::Unchecked2DAt(UInt_t i, UInt_t j) const                    
36 //       return &(  ((char**)fCont)[i] [j*fObjectSize]); 
37 //       void  *  AliMemArray::Unchecked2DAt(UInt_t i) const 
38 //       return &(  ((char**)fCont)[i/fBufferSize] [(i%fBufferSize)*fObjectSize])  ;
39
40
41 //Begin_Html
42 //<img src="../gif/AliMemArray.gif">
43 //End_Html
44
45    
46 //  Streamer CTORBuffer and DTORBuffer are  virtual - should be implemented in derived
47 //  classes. For example AliObjectArray derived from AliMemArray is general array 
48 //  for objects with defined AliClassInfo information. 
49 //                                                                           //
50 //                                                                          //
51 //  Origin:  Marian Ivanov, Uni. of Bratislava, ivanov@fmph.uniba.sk // 
52 ///////////////////////////////////////////////////////////////////////////////
53
54
55
56 #include "AliMemArray.h"
57 #include "Riostream.h"
58 #include "TMath.h"
59 #include "TError.h"
60
61
62 ClassImp(AliMemArray)
63  
64
65 AliMemArray::AliMemArray()
66
67   //
68   //default constructor
69   //
70   fCont = 0;
71   fSize = 0;
72   fCapacity=0;
73   fObjectSize = 0;
74   fBufferSize = 0;
75 }
76
77 AliMemArray::AliMemArray(Int_t objectSize, Int_t buffersize)
78 {
79   //
80   // AliMemArray constructor 
81   fCont = 0;
82   fSize = 0;
83   fCapacity=0;
84   fObjectSize =objectSize;
85   fBufferSize  =buffersize;
86 }
87
88 AliMemArray::AliMemArray(const AliMemArray & arr):
89   TObject(arr)
90 {
91   //
92   //copy constructor
93   fCont = arr.fCont;
94   fSize = arr.fSize;
95   fCapacity = arr.fCapacity;
96   fObjectSize = arr.fObjectSize;
97   fBufferSize =arr.fBufferSize;
98   
99   if (arr.fBufferSize==0) {
100     fCont = new char[fCapacity*fObjectSize];
101     CopyBuffer(fCont, arr.fCont, fSize);
102   }
103   else{ 
104     Int_t buffers = fCapacity/fBufferSize;
105     if (fCapacity%fBufferSize) buffers++;     
106     void ** table  = (void**) new char*[buffers];   
107     for (Int_t i=0; i<buffers;i++){
108       table[i] = new char[fBufferSize*fObjectSize];
109       Int_t size = fSize - i*fBufferSize;
110       if (size > (Int_t)fBufferSize) size = fBufferSize;
111       if (size >0) CopyBuffer(table[i], ((void**)arr.fCont)[i],size);
112     }
113     fCont = (void*)table;
114   }
115 }
116     
117
118 void AliMemArray::Swap(  AliMemArray &arr)
119 {
120   //swap contents of array
121   UInt_t size = arr.fSize;
122   arr.fSize = fSize;
123   fSize = size;
124   UInt_t capacity = arr.fCapacity;
125   arr.fCapacity = fCapacity;
126   fCapacity = capacity;
127   UInt_t objectSize = arr.fObjectSize;
128   arr.fObjectSize = fObjectSize;
129   fObjectSize = objectSize;
130   UInt_t bufferSize = arr.fBufferSize;
131   arr.fBufferSize = fBufferSize;
132   fBufferSize = bufferSize;
133   void * cont = arr.fCont;
134   arr.fCont = fCont;
135   fCont = cont;
136 }
137
138 void     AliMemArray::CopyBuffer(void *dest, void *src,  UInt_t size)
139 {
140   //
141   //array placement copy constructor
142   memcpy(dest, src,size*fObjectSize);
143 }
144
145 AliMemArray::~AliMemArray()  
146 {
147   //
148   //default destructor
149   Delete();
150 }
151
152
153 void   AliMemArray::SetObjectSize(UInt_t  bufsize)
154 {
155   //
156   //set memory size for one object - it can be changed only when the array is empty 
157   if (fCont){
158     ::Error("AliMemArray::SetObjectSize", "forbidden to resize just allocated objects");
159     return;
160   };
161   fBufferSize=bufsize;
162 }
163
164 AliMemArray & AliMemArray::operator = (const AliMemArray &arr)
165 {
166   //
167   //
168   AliMemArray  tmparr(arr);
169   Swap(tmparr);
170   return *this;
171 }
172
173 void   AliMemArray::SetBufferSize(UInt_t  bufsize)
174 {
175   //
176   //set buffer size - it can be changed only when the array is empty 
177   if (fCont==0) {
178     fBufferSize = bufsize;
179     return;
180   }
181   if (fBufferSize == bufsize) return;
182   
183   if (bufsize==0){
184     char *table = new char[fObjectSize*fCapacity];
185     char * p = table;
186     for (UInt_t i=0; i<fSize; i++,p+=fObjectSize) 
187       memcpy(p, At(i), fObjectSize);
188     //delete [](char*)fCont;
189     Delete();
190     fCont = table;
191     fBufferSize = bufsize;
192   }
193   else{
194     Int_t buffers = fCapacity/bufsize;
195     if (fCapacity%bufsize) buffers++;     
196     char ** table  =  new char*[buffers];   
197     for (Int_t ibuf=0; ibuf<buffers;ibuf++){
198       table[ibuf] = new char[bufsize*fObjectSize];
199       Int_t size = fSize - ibuf*bufsize;
200       if (size > (Int_t)bufsize) size = bufsize;      
201       if (size >0) for ( Int_t ip=0;ip<size;ip++)
202         memcpy(&table[ibuf][ip*fObjectSize], At(ibuf*bufsize+ip), fObjectSize);
203     }
204     //    delete [](char**)fCont;
205     Delete();
206     fCont = (void*)table;
207     fBufferSize = bufsize;
208   }
209
210 }
211
212
213
214 void AliMemArray::Delete(Option_t *)
215 {
216   //
217   //delete memory space occupied by the array  - 
218   //Use this routine when your objects allocate
219   //memory (e.g. objects inheriting from TNamed or containing TStrings
220   //allocate memory). If not you better use Clear() since if is faster.  
221   if (fCont){
222     if (fBufferSize) {
223       Delete2D();
224       fSize = 0;
225       fCapacity = 0;
226       return;
227     }
228     DTORBuffer(Unchecked1DAt(0),fSize);
229     delete [] (char*)fCont;
230     fCont = 0;
231     fSize = 0;
232     fCapacity = 0;
233   }
234 }
235
236 void AliMemArray::Clear(Option_t *)
237 {
238   //
239   //clear array   - 
240   // Only use this routine when your objects don't
241   // allocate memory since it will not call the object dtors.
242   if (fBufferSize){
243     Clear2D();
244     return;
245   }
246   if (fCont){
247     //    memset(fCont, 0, fSize*fObjectSize);
248     //MI change - to have the same as in TClonesArray
249     fSize = 0;
250   }
251 }
252
253 void AliMemArray::Reserve(UInt_t  n)
254 {
255   //
256   //reserve arrays space
257   //  
258   if (fObjectSize<=0) {
259     cout<<"Object length not defined\n";
260     return;
261   }
262   if (n==fCapacity) return;
263   
264   if (fBufferSize>0) {
265     Reserve2D(n); //if 2D buffer
266     return;
267   }
268   //
269   if (fCapacity){
270     if (fSize>n) {
271       DTORBuffer(Unchecked1DAt(n),fSize-n);
272       memset(&((char*)fCont)[n*fObjectSize], 0, (fSize-n)*fObjectSize); 
273       fSize =n;
274     }
275     fCont = (char*)TStorage::ReAlloc(fCont, n*fObjectSize,fCapacity*fObjectSize); 
276   }
277   else  fCont = new char[n*fObjectSize];
278
279   if (!fCont) fCapacity = 0;
280   else fCapacity = n;
281 }
282
283
284 void AliMemArray::Resize(UInt_t  n)
285 {
286   //
287   //resize buffer
288   //   
289   if (fObjectSize<=0) {
290     cout<<"Object length not defined\n";
291     return;
292   }
293   if (fBufferSize>0) {
294      Resize2D(n); //if 2D buffer
295      return;
296   }
297   //
298   if (n>fCapacity) Reserve(2*n);   //reserve automaticaly space if sie >capacity
299   if (fSize>n){ 
300     DTORBuffer(Unchecked1DAt(n),fSize-n);
301     //memset(&((char*)fCont)[n*fObjectSize], 0, (fSize-n)*fObjectSize);
302     //MI change - to have the same as in TClonesArray
303   }
304   if (fSize<n)    CTORBuffer(Unchecked1DAt(fSize),n-fSize);     
305   fSize = n;
306   return; 
307 }
308
309 void AliMemArray::Delete2D()
310 {
311   //
312   //delete memory space occupied by the array 
313   if (!fBufferSize) return;
314
315   Int_t  nbuff = (fCapacity/fBufferSize);
316   if ( (fCapacity%fBufferSize)!=0) nbuff++;
317   for (Int_t  i=0;i<nbuff;i++) {    
318     Int_t size = fSize-i*fBufferSize;
319     if  (size>0)
320       DTORBuffer(GetRow(i),UInt_t(size)<fBufferSize? size:fBufferSize);    
321     delete [] (char*)GetRow(i);
322   }
323   delete [] (void**)fCont;
324   fCont =0;
325   fSize = 0;  
326   fCapacity = 0;
327 }
328
329 void AliMemArray::Clear2D()
330 {
331   //
332   //clear memory space occupied by the array  - doesn't call DTOR
333   Int_t  nbuff = (fCapacity/fBufferSize);
334   if ( (fCapacity%fBufferSize)!=0) nbuff++;
335   // for (Int_t  i=0;i<nbuff;i++) memset(GetRow(i), 0, fSize*fObjectSize);
336   //MI change - to have the same as in TClonesArray
337   fSize = 0;  
338 }
339
340
341
342
343 void AliMemArray::Reserve2D(UInt_t  n) 
344 {
345   //
346   // 
347   Int_t buffers = n/fBufferSize;
348   if (n%fBufferSize) buffers++;
349   UInt_t  nobjects=buffers*fBufferSize;
350   Int_t oldbuffers = GetNBuffers() ;
351   if (buffers==oldbuffers) return;
352   //
353   void ** table  = (void**) new char*[buffers];
354
355   Int_t max = buffers>oldbuffers ? buffers: oldbuffers;
356   for (Int_t i = 0;i<max;i++) {
357     if ( (i<oldbuffers) && (i<buffers))  table[i] = GetRow(i);
358     if ( (i<oldbuffers)&&(i>=buffers) ){
359       Int_t dsize = TMath::Min(Int_t(fSize) - i*Int_t(fBufferSize),Int_t(fBufferSize));
360       if (dsize>0) DTORBuffer(GetRow(i),dsize);
361       delete [] (char*)GetRow(i);
362     }
363     if (i>=oldbuffers)
364       table[i] = new char[fBufferSize*fObjectSize];
365   }
366   if (fSize>nobjects) fSize=nobjects;
367
368   fCapacity = nobjects ;    
369   delete [] (void**)fCont;
370   fCont = (void*)table;
371 }
372
373
374
375 void AliMemArray::Resize2D(UInt_t  n) 
376 {
377   //
378   //  
379   if (n>fCapacity) Reserve2D(n);   //reserve automaticaly space 
380   Int_t buffers = n/fBufferSize;
381   if (n%fBufferSize) buffers++;
382
383   if (fSize>n){   //call destructor if we decrease the size of array
384     Int_t oldbuffer = fSize/fBufferSize;
385     
386     for (Int_t i=buffers;i<oldbuffer; i++){
387       Int_t iold= fSize-i*fBufferSize;
388       if (iold>(Int_t)fBufferSize) iold= fBufferSize; 
389       Int_t inew= n -i*fBufferSize;
390       if (inew<0) inew =0;
391       DTORBuffer(Unchecked2DAt(i,inew),iold-inew);
392     }
393   }
394   if (fSize<n){   //call constructor if we increase the size of array
395     Int_t oldbuffer = fSize/fBufferSize;
396     for (Int_t i=oldbuffer;i<buffers; i++){
397       Int_t iold = fSize-i*fBufferSize;
398       if (iold<0) iold = 0;
399       Int_t inew =  n -i*fBufferSize;
400       if (inew>(Int_t)fBufferSize) inew = fBufferSize;
401       CTORBuffer(Unchecked2DAt(i,iold),inew-iold);
402     }
403   }
404   fSize = n;  
405 }
406
407
408
409
410
411