Array.hxx

Go to the documentation of this file.
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 

Generated on Tue Aug 12 22:33:41 2008 for CLAM by  doxygen 1.5.5