|
CLAM-Development
1.3
|
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 SetElem(int where,const T& elem) 00210 { 00211 CLAM_DEBUG_ASSERT(where>=0,msgIndexOutOfRange); 00212 CLAM_DEBUG_ASSERT(where<mSize,msgIndexOutOfRange); 00213 mpData[where] = elem; 00214 } 00215 void DeleteElem(int where) 00216 { 00217 CLAM_ASSERT(OwnsMemory(),"Array::DeleteElem(): Resize requiered," 00218 " but this array does not own its memory!"); 00219 CLAM_ASSERT(where>-1 ,msgDeleteOutOfRange); 00220 CLAM_ASSERT(where<mSize,msgDeleteOutOfRange); 00221 DeleteElemInDataBuffer(where); 00222 mSize--; 00223 if (mSize<mAllocSize-mStep) 00224 Resize(mSize); 00225 } 00226 00227 Array<T>& operator = (const Array<T>& src) 00228 { 00229 00230 if ( OwnsMemory() ) 00231 { 00232 if ( Size() != src.Size() ) 00233 Resize( src.Size() ); 00234 if ( src.OwnsMemory() ) 00235 mStep = src.mStep; 00236 else 00237 mStep = 1; 00238 } 00239 else 00240 { 00241 CLAM_ASSERT( AllocatedSize() >= src.Size(), 00242 "Array::RegionWrite() : source size exceeds the Region bounds" ); 00243 CLAM_ASSERT( GetPtr() != NULL, 00244 "Array::operator= : if you want to create a not memory owning array " 00245 "from one that does own memory, use instead Array::SetPtr() method"); 00246 } 00247 00248 int tocopy = (src.Size()<Size())?src.Size():Size(); 00249 CopyDataBlock(0,tocopy,src.GetPtr()); 00250 InitializeCopyDataBlock(tocopy,src.Size(),src.GetPtr()); 00251 mSize=src.Size(); 00252 00253 return *this; 00254 00255 } 00256 00257 Array<T>& operator += (const Array<T>& src) 00258 { 00259 int start = Size(); 00260 Resize(Size()+src.Size()); 00261 mSize+=src.Size(); 00262 int end = Size(); 00263 InitializeCopyDataBlock(start,end,0,src.mpData); 00264 return *this; 00265 } 00266 00267 void Apply( T (*f)(T) ) 00268 { 00269 int i; 00270 for (i=0; i<mSize; i++) 00271 (*this)[i] = f( (*this)[i] ); 00272 } 00273 00274 void Apply( T (*f)(T,int),int parameter ) 00275 { 00276 int i; 00277 for (i=0; i<mSize; i++) 00278 (*this)[i] = f( (*this)[i], parameter ); 00279 } 00280 00281 void StoreOn(Storage & storage) const 00282 { 00283 StoreBufferOn((typename TypeInfo<T>::StorableAsLeaf *)NULL, mpData, storage); 00284 } 00285 void LoadFrom(Storage & storage) 00286 { 00287 LoadBufferFrom((typename TypeInfo<T>::StorableAsLeaf *)NULL, mpData, storage); 00288 } 00289 00290 // Error messages, to ease tests a little while we decide 00291 // about error codes. 00292 static const char *msgSetSizeOutOfRange; 00293 static const char *msgIndexOutOfRange; 00294 static const char *msgInsertOutOfRange; 00295 static const char *msgDeleteOutOfRange; 00296 00297 private: 00298 inline void ResizeDataBuffer(int new_size); 00299 inline void DestroyDataBuffer(void); 00300 inline void InsertElemInDataBuffer(int position); 00301 inline void DeleteElemInDataBuffer(int position); 00302 inline void InitializeElement(int position); 00303 inline void InitializeDataBlock(int first, int last); 00304 inline void UninitializeDataBlock(int first, int last); 00305 inline void CopyDataBlock(int first, int last, const T* src); 00306 inline void InitializeCopyDataBlock(int first, int last, const T* src); 00307 inline void InitializeCopyDataBlock(int first, int last, int src_first, const T* src); 00308 00309 void StoreBufferOn(StaticFalse* asLeave, const Component * polymorphicSelector, Storage & storage) const 00310 { 00311 if (mSize<=0) return; 00312 const char* className = mpData[0].GetClassName(); 00313 const char* label = className? className : "Element"; 00314 for (int i=0; i<mSize; i++) 00315 { 00316 XMLComponentAdapter adapter(mpData[i], label, true); 00317 storage.Store(adapter); 00318 } 00319 } 00320 void StoreBufferOn(StaticTrue* asLeave, const void * polymorphicSelector, Storage & storage) const 00321 { 00322 XMLAdapter<unsigned> sizeAdapter(Size(),"size"); 00323 storage.Store(sizeAdapter); 00324 XMLArrayAdapter<T> adapter(mpData,mSize); 00325 storage.Store(adapter); 00326 } 00327 void StoreBufferOn(StaticFalse* asLeave, const void * polymorphicSelector, Storage & storage) const 00328 { 00329 CLAM_ASSERT(false, 00330 "Trying to Store an object that is not neither a streamable nor a Component"); 00331 } 00332 void LoadBufferFrom(StaticFalse* asLeave, Component * polymorphicSelector, Storage & storage) 00333 { 00334 const char* label = 0; 00335 while (true) 00336 { 00337 T elem; 00338 if (!label) 00339 { 00340 label = elem.GetClassName(); 00341 if (!label) 00342 label = "Element"; 00343 } 00344 XMLComponentAdapter adapter(elem, label, true); 00345 if (!storage.Load(adapter)) return; 00346 AddElem(elem); 00347 } 00348 } 00349 void LoadBufferFrom(StaticTrue* asLeave, void * polymorphicSelector, Storage & storage) 00350 { 00351 unsigned size; 00352 XMLAdapter<unsigned> sizeAdapter(size,"size"); 00353 if (storage.Load(sizeAdapter)) 00354 { 00355 Resize(size); 00356 SetSize(size); 00357 XMLArrayAdapter<T> adapter(mpData,mSize); 00358 storage.Load(adapter); 00359 // TODO: if false, then insert an error on the storage 00360 return; 00361 } 00362 00363 while (true) { 00364 T elem; 00365 XMLAdapter<T> adapter(elem); 00366 if ( ! storage.Load(adapter)) return; 00367 AddElem(elem); 00368 } 00369 } 00370 void LoadBufferFrom(StaticFalse* asLeave, void * polymorphicSelector, Storage & storage) 00371 { 00372 CLAM_ASSERT(false, 00373 "Trying to Store an object that is not neither a streamable nor a Component"); 00374 } 00375 /* 00376 void StoreMemberOn(StaticTrue* asLeave, void * item, Storage & storage) const { 00377 XMLAdapter<T> adapter(*(T*)item); 00378 storage.Store(adapter); 00379 } 00380 void StoreMemberOn(StaticFalse* asLeave, Component * item, Storage & storage) const { 00381 const char* className = item->GetClassName(); 00382 const char* label = className? className : "Element"; 00383 XMLComponentAdapter adapter(*item, label, true); 00384 storage.Store(adapter); 00385 } 00386 bool StoreMemberOn(StaticFalse* asLeave, void * item, Storage & storage) { 00387 CLAM_ASSERT(false, "Trying to Store an object that is not neither a streamable nor a Component"); 00388 return false; 00389 } 00390 */ 00391 bool LoadMemberFrom(StaticTrue* asLeave, void * item, Storage & storage) { 00392 XMLAdapter<T> adapter(*(T*)item); 00393 return storage.Load(adapter); 00394 } 00395 bool LoadMemberFrom(StaticFalse* asLeave, Component * item, Storage & storage) { 00396 const char* className = (item->GetClassName()); 00397 const char* label = className? className : "Element"; 00398 XMLComponentAdapter adapter(*item, label, true); 00399 return storage.Load(adapter); 00400 } 00401 bool LoadMemberFrom(StaticFalse* asLeave, void * item, Storage & storage) { 00402 CLAM_ASSERT(false, "Trying to Load an object that is not neither a streamable nor a Component"); 00403 return false; 00404 } 00405 00406 }; 00407 00408 // Method implementations 00409 00410 00411 template<class T> 00412 void Array<T>::GiveChunk(int pos, int size, Array<T>& a) const 00413 { 00414 CLAM_ASSERT(pos + size <= mSize, 00415 "Array::GiveChunk(): Chunk out of bounds."); 00416 a.SetPtr(&mpData[pos],size); 00417 } 00418 00419 template<class T> 00420 void Array<T>::CopyChunk(int pos, int size, Array<T>& a) const 00421 { 00422 int last=pos+size; 00423 CLAM_ASSERT(last <= mSize, 00424 "Array::CopyChunk(): Chunk out of bounds."); 00425 CLAM_ASSERT(size <= a.mSize, 00426 "Array::CopyChunk(): destination array does not have enough memory"); 00427 for (int i=pos;i<last;i++) 00428 a.mpData[i-pos]=mpData[i]; 00429 } 00430 00431 template<class T> 00432 void Array<T>::InitializeElement(int i) 00433 { 00434 new (&mpData[i]) T(); 00435 } 00436 00437 template<class T> 00438 void Array<T>::InitializeDataBlock(int first, int last) 00439 { 00440 int i; 00441 for (i = first; i < last; i++) 00442 InitializeElement(i); 00443 } 00444 00445 template<class T> 00446 void Array<T>::UninitializeDataBlock(int first, int last) 00447 { 00448 int i; 00449 for (i = first; i < last; i++) 00450 (&mpData[i])->~T(); 00451 } 00452 00453 template<class T> 00454 void Array<T>::CopyDataBlock(int first, int last, const T* src) 00455 { 00456 int i; 00457 for (i=first; i<last ;i++) 00458 mpData[i]=src[i]; 00459 } 00460 00461 template<class T> 00462 void Array<T>::InitializeCopyDataBlock(int first, int last, const T* src) 00463 { 00464 int i; 00465 for (i=first; i<last; i++) 00466 new(&mpData[i]) T(src[i]); 00467 } 00468 00469 template<class T> 00470 void Array<T>::InitializeCopyDataBlock(int first, int last, int src_first, const T* src) 00471 { 00472 int i, j = src_first; 00473 for (i=first; i<last; i++) 00474 new (&mpData[i]) T(src[j++]); 00475 } 00476 00477 00478 template<class T> 00479 void Array<T>::DestroyDataBuffer() 00480 { 00481 if (OwnsMemory()) 00482 { 00483 UninitializeDataBlock(0,mSize); 00484 free(mpData); 00485 } 00486 mpData=NULL; 00487 } 00488 00490 template<class T> 00491 void Array<T>::ResizeDataBuffer(int new_size) 00492 { 00493 if (new_size == mAllocSize) 00494 return; 00495 T* old_data = mpData; 00496 mpData = (T*) malloc(new_size*sizeof(T)); 00497 if (!old_data) return; 00498 int elems = new_size; 00499 if (mSize < elems) 00500 elems = mSize; 00501 InitializeCopyDataBlock(0,elems,old_data); 00502 for (int i=0; i<mSize; i++) 00503 (&old_data[i])->~T(); 00504 free(old_data); 00505 } 00506 00514 template<class T> 00515 void Array<T>::InsertElemInDataBuffer(int position) 00516 { 00517 if (mSize>0) 00518 new(&mpData[mSize]) T(mpData[mSize-1]); 00519 for (int i=mSize-1; i>position; i--) 00520 mpData[i] = mpData[i-1]; 00521 (&mpData[position])->~T(); 00522 } 00523 00530 template<class T> 00531 void Array<T>::DeleteElemInDataBuffer(int position) 00532 { 00533 for (int i=position; i<mSize-1; i++) 00534 mpData[i] = mpData[i+1]; 00535 (&mpData[mSize-1])->~T(); 00536 } 00537 00538 00539 template <class T> inline Array<T> operator + ( 00540 const Array<T>& a,const Array<T>& b) 00541 { 00542 Array<T> ret = a; 00543 ret += b; 00544 return ret; 00545 } 00546 00547 template <class T> inline bool operator == ( 00548 const Array<T>& a,const Array<T>& b) 00549 { 00550 if (a.Size()!=b.Size()) return false; 00551 for (int i=0;i<a.Size();i++) 00552 { 00553 if (a[i]!=b[i]) return false; 00554 } 00555 return true; 00556 } 00557 00558 00559 00560 typedef Array<TData> DataArray; 00561 00562 template<class T> 00563 const char* Array<T>::msgSetSizeOutOfRange = 00564 "Array::SetSize(): Argument larger than allocated size\n" 00565 "You can probably fix this calling Resize() befor SetSize()."; 00566 00567 template<class T> 00568 const char* Array<T>::msgIndexOutOfRange = 00569 "Array::operator[]: Index out of range\n" 00570 "This may happen if you forgot to call SetSize(...) in your code.\n" 00571 "This is now needed. Just calling Resize() is not enough any more."; 00572 00573 template<class T> 00574 const char* Array<T>::msgInsertOutOfRange = 00575 "Array::InsertElem: Index out of range"; 00576 00577 template<class T> 00578 const char* Array<T>::msgDeleteOutOfRange = 00579 "Array::DeleteElem: Index out of range"; 00580 00581 } 00582 00583 #endif//_Array_ 00584
1.7.6.1