CLAM-Development
1.1
|
00001 /* 00002 * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG) 00003 * UNIVERSITAT POMPEU FABRA 00004 * 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 * 00020 */ 00021 00022 #ifndef _Array_ 00023 #define _Array_ 00024 00025 #include <cstdio> 00026 #include <cstdlib> 00027 #include <cstring> 00028 #include <new> 00029 #include "DataTypes.hxx" 00030 #include "Err.hxx" 00031 #include "Assert.hxx" 00032 #include "ErrOutOfMemory.hxx" 00033 #include "Storage.hxx" 00034 #include "Component.hxx" 00035 #include "TypeInfo.hxx" 00036 00037 // @todo Remove this include. See Bug#111 00038 #include "DynamicType.hxx" 00039 00040 00041 #include "XMLAdapter.hxx" 00042 #include "XMLArrayAdapter.hxx" 00043 #include "XMLComponentAdapter.hxx" 00044 00045 namespace CLAM { 00046 00047 00048 00049 template <class T> class Array:public Component 00050 { 00051 private: 00052 T *mpData; 00053 TSize mAllocSize; 00054 TSize mSize; 00055 int mStep; 00056 public: 00057 Array(TSize size = 0,TSize step = 1) 00058 { 00059 mSize = mAllocSize = 0; 00060 mStep = step; 00061 mpData = NULL; 00062 Resize(size); 00063 SetSize(size); 00064 } 00065 00066 void Init(){ 00067 Resize(0); 00068 SetSize(0);} 00069 00070 Array(T* ptr,int size = 0) 00071 { 00072 CLAM_ASSERT( ptr!=NULL, 00073 "Array::Array( T*, int) : you cannot create a not-owning memory array " 00074 "without specifying a valid data pointer. "); 00075 mSize = mAllocSize = size; 00076 mStep = -1; 00077 mpData = ptr; 00078 } 00079 00080 Array(const Array<T> &originalArray) 00081 { 00082 mpData = NULL; 00083 mSize = mAllocSize = mStep = 0; 00084 *this = originalArray; 00085 } 00086 00087 ~Array() 00088 { 00089 DestroyDataBuffer(); 00090 mAllocSize=mSize=mStep=0; 00091 } 00092 00093 const char * GetClassName() const {return NULL;} 00094 00095 bool OwnsMemory() const {return mStep>=0; } 00096 bool Empty() const { return mSize==0; } 00097 00098 TSize Size(void) const { return mSize; } 00099 TSize SizeInBytes(void) const { return mSize*sizeof(T); } 00100 TSize AllocatedSize(void) const { return mAllocSize; } 00101 TSize AllocatedSizeInBytes(void) const { return mAllocSize*sizeof(T); } 00102 00103 void SetSize(TSize size) 00104 { 00105 CLAM_ASSERT(size <= AllocatedSize() || !OwnsMemory(), msgSetSizeOutOfRange); 00106 if (OwnsMemory()) 00107 { 00108 if (size > mSize) 00109 InitializeDataBlock(mSize,size); 00110 if (size < mSize) 00111 UninitializeDataBlock(size,mSize); 00112 } 00113 mSize = size; 00114 } 00115 00116 void SetStep(TSize step) { mStep = step;} 00117 00118 TSize GetStep() const {return mStep;} 00119 00120 void Resize(TSize newAllocSize) 00121 { 00122 CLAM_ASSERT(OwnsMemory(), 00123 "Array::Resize(): You cannot invoke this method on an array that " 00124 "does not own any memory" ); 00125 CLAM_ASSERT( newAllocSize >= 0, 00126 "Array::Resize(): You are trying to allocate a negative amount of " 00127 "space, which is a weird thing to do, isn't it?"); 00128 00129 /* calculate the amount of bytes to allocate */ 00130 /* effectively resize the array by allocating more memory */ 00131 if(newAllocSize>0) 00132 ResizeDataBuffer(newAllocSize); 00133 else 00134 { 00135 if(mpData) 00136 { 00137 DestroyDataBuffer(); 00138 mpData=NULL; 00139 } 00140 } 00141 00142 mAllocSize = newAllocSize; 00143 00144 if (mAllocSize<mSize) 00145 mSize = mAllocSize; 00146 00147 /* if the pointer to the end of the array is over then you're out of memory */ 00148 /* and an error message will be sent to the console */ 00149 CLAM_ASSERT( AllocatedSize()==0 || mpData!=NULL, 00150 "Array::Resize() : Memory Allocation failed!" ); 00151 } 00152 00153 const T* GetPtr(void) const { return mpData; } 00154 T* GetPtr(void) { return mpData; } 00155 00156 void SetPtr(T* ptr, int size = 0) 00157 { 00158 CLAM_ASSERT( !OwnsMemory() || mAllocSize == 0, 00159 "Array::SetPtr() : You are not allowed to invoke SetPtr() on" 00160 " an Array that owns memory or is not empty" ); 00161 00162 mSize = mAllocSize = size; 00163 mpData = ptr; 00164 00165 if (ptr == 0 && size == 0) 00166 mStep = 1; // Sets the array to empty state. 00167 else 00168 mStep = -1; // the array gets not owner of the new data. 00169 } 00170 00171 inline void GiveChunk(int pos, int size, Array<T>&) const; 00172 00173 inline void CopyChunk(int pos, int size, Array<T>&) const; 00174 00175 const T& operator [](const int& i) const 00176 { 00177 CLAM_DEBUG_ASSERT(i>=0,msgIndexOutOfRange); 00178 CLAM_DEBUG_ASSERT(i<mSize,msgIndexOutOfRange); 00179 return mpData[i]; 00180 } 00181 00182 T& operator [](const int& i) 00183 { 00184 CLAM_DEBUG_ASSERT(i>=0,msgIndexOutOfRange); 00185 CLAM_DEBUG_ASSERT(i<mSize,msgIndexOutOfRange); 00186 return mpData[i]; 00187 } 00188 00189 void AddElem(const T& elem) 00190 { 00191 CLAM_ASSERT(OwnsMemory(),"Array::AddElem(): Resize requiered," 00192 " but this array does not own its memory!"); 00193 if (mSize>=mAllocSize) 00194 Resize(mAllocSize+mStep); 00195 new(&mpData[mSize]) T(elem); 00196 mSize++; 00197 } 00198 void InsertElem(int where,const T& elem) 00199 { 00200 CLAM_ASSERT(OwnsMemory(),"Array::InsertElem(): Resize requiered," 00201 " but this array does not own its memory!"); 00202 CLAM_ASSERT( (where>=0) && (where<mSize) ,msgInsertOutOfRange); 00203 if (mSize>=mAllocSize) 00204 Resize(mAllocSize+mStep); 00205 InsertElemInDataBuffer(where); 00206 new(&mpData[where]) T(elem); 00207 mSize++; 00208 } 00209 void DeleteElem(int where) 00210 { 00211 CLAM_ASSERT(OwnsMemory(),"Array::DeleteElem(): Resize requiered," 00212 " but this array does not own its memory!"); 00213 CLAM_ASSERT(where>-1 ,msgDeleteOutOfRange); 00214 CLAM_ASSERT(where<mSize,msgDeleteOutOfRange); 00215 DeleteElemInDataBuffer(where); 00216 mSize--; 00217 if (mSize<mAllocSize-mStep) 00218 Resize(mSize); 00219 } 00220 00221 Array<T>& operator = (const Array<T>& src) 00222 { 00223 00224 if ( OwnsMemory() ) 00225 { 00226 if ( Size() != src.Size() ) 00227 Resize( src.Size() ); 00228 if ( src.OwnsMemory() ) 00229 mStep = src.mStep; 00230 else 00231 mStep = 1; 00232 } 00233 else 00234 { 00235 CLAM_ASSERT( AllocatedSize() >= src.Size(), 00236 "Array::RegionWrite() : source size exceeds the Region bounds" ); 00237 CLAM_ASSERT( GetPtr() != NULL, 00238 "Array::operator= : if you want to create a not memory owning array " 00239 "from one that does own memory, use instead Array::SetPtr() method"); 00240 } 00241 00242 int tocopy = (src.Size()<Size())?src.Size():Size(); 00243 CopyDataBlock(0,tocopy,src.GetPtr()); 00244 InitializeCopyDataBlock(tocopy,src.Size(),src.GetPtr()); 00245 mSize=src.Size(); 00246 00247 return *this; 00248 00249 } 00250 00251 Array<T>& operator += (const Array<T>& src) 00252 { 00253 int start = Size(); 00254 Resize(Size()+src.Size()); 00255 mSize+=src.Size(); 00256 int end = Size(); 00257 InitializeCopyDataBlock(start,end,0,src.mpData); 00258 return *this; 00259 } 00260 00261 void Apply( T (*f)(T) ) 00262 { 00263 int i; 00264 for (i=0; i<mSize; i++) 00265 (*this)[i] = f( (*this)[i] ); 00266 } 00267 00268 void Apply( T (*f)(T,int),int parameter ) 00269 { 00270 int i; 00271 for (i=0; i<mSize; i++) 00272 (*this)[i] = f( (*this)[i], parameter ); 00273 } 00274 00275 void StoreOn(Storage & storage) const 00276 { 00277 StoreBufferOn((typename TypeInfo<T>::StorableAsLeaf *)NULL, mpData, storage); 00278 } 00279 void LoadFrom(Storage & storage) 00280 { 00281 LoadBufferFrom((typename TypeInfo<T>::StorableAsLeaf *)NULL, mpData, storage); 00282 } 00283 00284 // Error messages, to ease tests a little while we decide 00285 // about error codes. 00286 static const char *msgSetSizeOutOfRange; 00287 static const char *msgIndexOutOfRange; 00288 static const char *msgInsertOutOfRange; 00289 static const char *msgDeleteOutOfRange; 00290 00291 private: 00292 inline void ResizeDataBuffer(int new_size); 00293 inline void DestroyDataBuffer(void); 00294 inline void InsertElemInDataBuffer(int position); 00295 inline void DeleteElemInDataBuffer(int position); 00296 inline void InitializeElement(int position); 00297 inline void InitializeDataBlock(int first, int last); 00298 inline void UninitializeDataBlock(int first, int last); 00299 inline void CopyDataBlock(int first, int last, const T* src); 00300 inline void InitializeCopyDataBlock(int first, int last, const T* src); 00301 inline void InitializeCopyDataBlock(int first, int last, int src_first, const T* src); 00302 00303 void StoreBufferOn(StaticFalse* asLeave, const Component * polymorphicSelector, Storage & storage) const 00304 { 00305 if (mSize<=0) return; 00306 const char* className = mpData[0].GetClassName(); 00307 const char* label = className? className : "Element"; 00308 for (int i=0; i<mSize; i++) 00309 { 00310 XMLComponentAdapter adapter(mpData[i], label, true); 00311 storage.Store(adapter); 00312 } 00313 } 00314 void StoreBufferOn(StaticTrue* asLeave, const void * polymorphicSelector, Storage & storage) const 00315 { 00316 XMLAdapter<unsigned> sizeAdapter(Size(),"size"); 00317 storage.Store(sizeAdapter); 00318 XMLArrayAdapter<T> adapter(mpData,mSize); 00319 storage.Store(adapter); 00320 } 00321 void StoreBufferOn(StaticFalse* asLeave, const void * polymorphicSelector, Storage & storage) const 00322 { 00323 CLAM_ASSERT(false, 00324 "Trying to Store an object that is not neither a streamable nor a Component"); 00325 } 00326 void LoadBufferFrom(StaticFalse* asLeave, Component * polymorphicSelector, Storage & storage) 00327 { 00328 const char* label = 0; 00329 while (true) 00330 { 00331 T elem; 00332 if (!label) 00333 { 00334 label = elem.GetClassName(); 00335 if (!label) 00336 label = "Element"; 00337 } 00338 XMLComponentAdapter adapter(elem, label, true); 00339 if (!storage.Load(adapter)) return; 00340 AddElem(elem); 00341 } 00342 } 00343 void LoadBufferFrom(StaticTrue* asLeave, void * polymorphicSelector, Storage & storage) 00344 { 00345 unsigned size; 00346 XMLAdapter<unsigned> sizeAdapter(size,"size"); 00347 if (storage.Load(sizeAdapter)) 00348 { 00349 Resize(size); 00350 SetSize(size); 00351 XMLArrayAdapter<T> adapter(mpData,mSize); 00352 storage.Load(adapter); 00353 // TODO: if false, then insert an error on the storage 00354 return; 00355 } 00356 00357 while (true) { 00358 T elem; 00359 XMLAdapter<T> adapter(elem); 00360 if ( ! storage.Load(adapter)) return; 00361 AddElem(elem); 00362 } 00363 } 00364 void LoadBufferFrom(StaticFalse* asLeave, void * polymorphicSelector, Storage & storage) 00365 { 00366 CLAM_ASSERT(false, 00367 "Trying to Store an object that is not neither a streamable nor a Component"); 00368 } 00369 /* 00370 void StoreMemberOn(StaticTrue* asLeave, void * item, Storage & storage) const { 00371 XMLAdapter<T> adapter(*(T*)item); 00372 storage.Store(adapter); 00373 } 00374 void StoreMemberOn(StaticFalse* asLeave, Component * item, Storage & storage) const { 00375 const char* className = item->GetClassName(); 00376 const char* label = className? className : "Element"; 00377 XMLComponentAdapter adapter(*item, label, true); 00378 storage.Store(adapter); 00379 } 00380 bool StoreMemberOn(StaticFalse* asLeave, void * item, Storage & storage) { 00381 CLAM_ASSERT(false, "Trying to Store an object that is not neither a streamable nor a Component"); 00382 return false; 00383 } 00384 */ 00385 bool LoadMemberFrom(StaticTrue* asLeave, void * item, Storage & storage) { 00386 XMLAdapter<T> adapter(*(T*)item); 00387 return storage.Load(adapter); 00388 } 00389 bool LoadMemberFrom(StaticFalse* asLeave, Component * item, Storage & storage) { 00390 const char* className = (item->GetClassName()); 00391 const char* label = className? className : "Element"; 00392 XMLComponentAdapter adapter(*item, label, true); 00393 return storage.Load(adapter); 00394 } 00395 bool LoadMemberFrom(StaticFalse* asLeave, void * item, Storage & storage) { 00396 CLAM_ASSERT(false, "Trying to Load an object that is not neither a streamable nor a Component"); 00397 return false; 00398 } 00399 00400 }; 00401 00402 // Method implementations 00403 00404 00405 template<class T> 00406 void Array<T>::GiveChunk(int pos, int size, Array<T>& a) const 00407 { 00408 CLAM_ASSERT(pos + size <= mSize, 00409 "Array::GiveChunk(): Chunk out of bounds."); 00410 a.SetPtr(&mpData[pos],size); 00411 } 00412 00413 template<class T> 00414 void Array<T>::CopyChunk(int pos, int size, Array<T>& a) const 00415 { 00416 int last=pos+size; 00417 CLAM_ASSERT(last <= mSize, 00418 "Array::CopyChunk(): Chunk out of bounds."); 00419 CLAM_ASSERT(size <= a.mSize, 00420 "Array::CopyChunk(): destination array does not have enough memory"); 00421 for (int i=pos;i<last;i++) 00422 a.mpData[i-pos]=mpData[i]; 00423 } 00424 00425 template<class T> 00426 void Array<T>::InitializeElement(int i) 00427 { 00428 new (&mpData[i]) T(); 00429 } 00430 00431 template<class T> 00432 void Array<T>::InitializeDataBlock(int first, int last) 00433 { 00434 int i; 00435 for (i = first; i < last; i++) 00436 InitializeElement(i); 00437 } 00438 00439 template<class T> 00440 void Array<T>::UninitializeDataBlock(int first, int last) 00441 { 00442 int i; 00443 for (i = first; i < last; i++) 00444 (&mpData[i])->~T(); 00445 } 00446 00447 template<class T> 00448 void Array<T>::CopyDataBlock(int first, int last, const T* src) 00449 { 00450 int i; 00451 for (i=first; i<last ;i++) 00452 mpData[i]=src[i]; 00453 } 00454 00455 template<class T> 00456 void Array<T>::InitializeCopyDataBlock(int first, int last, const T* src) 00457 { 00458 int i; 00459 for (i=first; i<last; i++) 00460 new(&mpData[i]) T(src[i]); 00461 } 00462 00463 template<class T> 00464 void Array<T>::InitializeCopyDataBlock(int first, int last, int src_first, const T* src) 00465 { 00466 int i, j = src_first; 00467 for (i=first; i<last; i++) 00468 new (&mpData[i]) T(src[j++]); 00469 } 00470 00471 00472 template<class T> 00473 void Array<T>::DestroyDataBuffer() 00474 { 00475 if (OwnsMemory()) 00476 { 00477 UninitializeDataBlock(0,mSize); 00478 free(mpData); 00479 } 00480 mpData=NULL; 00481 } 00482 00484 template<class T> 00485 void Array<T>::ResizeDataBuffer(int new_size) 00486 { 00487 if (new_size == mAllocSize) 00488 return; 00489 T* old_data = mpData; 00490 mpData = (T*) malloc(new_size*sizeof(T)); 00491 if (!old_data) return; 00492 int elems = new_size; 00493 if (mSize < elems) 00494 elems = mSize; 00495 InitializeCopyDataBlock(0,elems,old_data); 00496 for (int i=0; i<mSize; i++) 00497 (&old_data[i])->~T(); 00498 free(old_data); 00499 } 00500 00508 template<class T> 00509 void Array<T>::InsertElemInDataBuffer(int position) 00510 { 00511 if (mSize>0) 00512 new(&mpData[mSize]) T(mpData[mSize-1]); 00513 for (int i=mSize-1; i>position; i--) 00514 mpData[i] = mpData[i-1]; 00515 (&mpData[position])->~T(); 00516 } 00517 00524 template<class T> 00525 void Array<T>::DeleteElemInDataBuffer(int position) 00526 { 00527 for (int i=position; i<mSize-1; i++) 00528 mpData[i] = mpData[i+1]; 00529 (&mpData[mSize-1])->~T(); 00530 } 00531 00532 00533 template <class T> inline Array<T> operator + ( 00534 const Array<T>& a,const Array<T>& b) 00535 { 00536 Array<T> ret = a; 00537 ret += b; 00538 return ret; 00539 } 00540 00541 template <class T> inline bool operator == ( 00542 const Array<T>& a,const Array<T>& b) 00543 { 00544 if (a.Size()!=b.Size()) return false; 00545 for (int i=0;i<a.Size();i++) 00546 { 00547 if (a[i]!=b[i]) return false; 00548 } 00549 return true; 00550 } 00551 00552 00553 00554 typedef Array<TData> DataArray; 00555 00556 template<class T> 00557 const char* Array<T>::msgSetSizeOutOfRange = 00558 "Array::SetSize(): Argument larger than allocated size\n" 00559 "You can probably fix this calling Resize() befor SetSize()."; 00560 00561 template<class T> 00562 const char* Array<T>::msgIndexOutOfRange = 00563 "Array::operator[]: Index out of range\n" 00564 "This may happen if you forgot to call SetSize(...) in your code.\n" 00565 "This is now needed. Just calling Resize() is not enough any more."; 00566 00567 template<class T> 00568 const char* Array<T>::msgInsertOutOfRange = 00569 "Array::InsertElem: Index out of range"; 00570 00571 template<class T> 00572 const char* Array<T>::msgDeleteOutOfRange = 00573 "Array::DeleteElem: Index out of range"; 00574 00575 } 00576 00577 #endif//_Array_ 00578