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    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 
Generated by  doxygen 1.6.3