CLAM-Development  1.4.0
Array.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG)
3  * UNIVERSITAT POMPEU FABRA
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
22 #ifndef _Array_
23 #define _Array_
24 
25 #include <cstdio>
26 #include <cstdlib>
27 #include <cstring>
28 #include <new>
29 #include "DataTypes.hxx"
30 #include "Err.hxx"
31 #include "Assert.hxx"
32 #include "ErrOutOfMemory.hxx"
33 #include "Storage.hxx"
34 #include "Component.hxx"
35 #include "TypeInfo.hxx"
36 
37 // @todo Remove this include. See Bug#111
38 #include "DynamicType.hxx"
39 
40 
41 #include "XMLAdapter.hxx"
42 #include "XMLArrayAdapter.hxx"
43 #include "XMLComponentAdapter.hxx"
44 
45 namespace CLAM {
46 
47 
48 
49 template <class T> class Array:public Component
50 {
51 private:
52  T *mpData;
53  TSize mAllocSize;
54  TSize mSize;
55  int mStep;
56 public:
57  Array(TSize size = 0,TSize step = 1)
58  {
59  mSize = mAllocSize = 0;
60  mStep = step;
61  mpData = NULL;
62  Resize(size);
63  SetSize(size);
64  }
65 
66  void Init(){
67  Resize(0);
68  SetSize(0);}
69 
70  Array(T* ptr,int size = 0)
71  {
72  CLAM_ASSERT( ptr!=NULL,
73  "Array::Array( T*, int) : you cannot create a not-owning memory array "
74  "without specifying a valid data pointer. ");
75  mSize = mAllocSize = size;
76  mStep = -1;
77  mpData = ptr;
78  }
79 
80  Array(const Array<T> &originalArray)
81  {
82  mpData = NULL;
83  mSize = mAllocSize = mStep = 0;
84  *this = originalArray;
85  }
86 
88  {
89  DestroyDataBuffer();
90  mAllocSize=mSize=mStep=0;
91  }
92 
93  const char * GetClassName() const {return NULL;}
94 
95  bool OwnsMemory() const {return mStep>=0; }
96  bool Empty() const { return mSize==0; }
97 
98  TSize Size(void) const { return mSize; }
99  TSize SizeInBytes(void) const { return mSize*sizeof(T); }
100  TSize AllocatedSize(void) const { return mAllocSize; }
101  TSize AllocatedSizeInBytes(void) const { return mAllocSize*sizeof(T); }
102 
103  void SetSize(TSize size)
104  {
106  if (OwnsMemory())
107  {
108  if (size > mSize)
109  InitializeDataBlock(mSize,size);
110  if (size < mSize)
111  UninitializeDataBlock(size,mSize);
112  }
113  mSize = size;
114  }
115 
116  void SetStep(TSize step) { mStep = step;}
117 
118  TSize GetStep() const {return mStep;}
119 
120  void Resize(TSize newAllocSize)
121  {
123  "Array::Resize(): You cannot invoke this method on an array that "
124  "does not own any memory" );
125  CLAM_ASSERT( newAllocSize >= 0,
126  "Array::Resize(): You are trying to allocate a negative amount of "
127  "space, which is a weird thing to do, isn't it?");
128 
129  /* calculate the amount of bytes to allocate */
130  /* effectively resize the array by allocating more memory */
131  if(newAllocSize>0)
132  ResizeDataBuffer(newAllocSize);
133  else
134  {
135  if(mpData)
136  {
137  DestroyDataBuffer();
138  mpData=NULL;
139  }
140  }
141 
142  mAllocSize = newAllocSize;
143 
144  if (mAllocSize<mSize)
145  mSize = mAllocSize;
146 
147  /* if the pointer to the end of the array is over then you're out of memory */
148  /* and an error message will be sent to the console */
149  CLAM_ASSERT( AllocatedSize()==0 || mpData!=NULL,
150  "Array::Resize() : Memory Allocation failed!" );
151  }
152 
153  const T* GetPtr(void) const { return mpData; }
154  T* GetPtr(void) { return mpData; }
155 
156  void SetPtr(T* ptr, int size = 0)
157  {
158  CLAM_ASSERT( !OwnsMemory() || mAllocSize == 0,
159  "Array::SetPtr() : You are not allowed to invoke SetPtr() on"
160  " an Array that owns memory or is not empty" );
161 
162  mSize = mAllocSize = size;
163  mpData = ptr;
164 
165  if (ptr == 0 && size == 0)
166  mStep = 1; // Sets the array to empty state.
167  else
168  mStep = -1; // the array gets not owner of the new data.
169  }
170 
171  inline void GiveChunk(int pos, int size, Array<T>&) const;
172 
173  inline void CopyChunk(int pos, int size, Array<T>&) const;
174 
175  const T& operator [](const int& i) const
176  {
179  return mpData[i];
180  }
181 
182  T& operator [](const int& i)
183  {
186  return mpData[i];
187  }
188 
189  void AddElem(const T& elem)
190  {
191  CLAM_ASSERT(OwnsMemory(),"Array::AddElem(): Resize requiered,"
192  " but this array does not own its memory!");
193  if (mSize>=mAllocSize)
194  Resize(mAllocSize+mStep);
195  new(&mpData[mSize]) T(elem);
196  mSize++;
197  }
198  void InsertElem(int where,const T& elem)
199  {
200  CLAM_ASSERT(OwnsMemory(),"Array::InsertElem(): Resize requiered,"
201  " but this array does not own its memory!");
202  CLAM_ASSERT( (where>=0) && (where<mSize) ,msgInsertOutOfRange);
203  if (mSize>=mAllocSize)
204  Resize(mAllocSize+mStep);
205  InsertElemInDataBuffer(where);
206  new(&mpData[where]) T(elem);
207  mSize++;
208  }
209  void SetElem(int where,const T& elem)
210  {
213  mpData[where] = elem;
214  }
215  void DeleteElem(int where)
216  {
217  CLAM_ASSERT(OwnsMemory(),"Array::DeleteElem(): Resize requiered,"
218  " but this array does not own its memory!");
219  CLAM_ASSERT(where>-1 ,msgDeleteOutOfRange);
220  CLAM_ASSERT(where<mSize,msgDeleteOutOfRange);
221  DeleteElemInDataBuffer(where);
222  mSize--;
223  if (mSize<mAllocSize-mStep)
224  Resize(mSize);
225  }
226 
228  {
229 
230  if ( OwnsMemory() )
231  {
232  if ( Size() != src.Size() )
233  Resize( src.Size() );
234  if ( src.OwnsMemory() )
235  mStep = src.mStep;
236  else
237  mStep = 1;
238  }
239  else
240  {
241  CLAM_ASSERT( AllocatedSize() >= src.Size(),
242  "Array::RegionWrite() : source size exceeds the Region bounds" );
243  CLAM_ASSERT( GetPtr() != NULL,
244  "Array::operator= : if you want to create a not memory owning array "
245  "from one that does own memory, use instead Array::SetPtr() method");
246  }
247 
248  int tocopy = (src.Size()<Size())?src.Size():Size();
249  CopyDataBlock(0,tocopy,src.GetPtr());
250  InitializeCopyDataBlock(tocopy,src.Size(),src.GetPtr());
251  mSize=src.Size();
252 
253  return *this;
254 
255  }
256 
258  {
259  int start = Size();
260  Resize(Size()+src.Size());
261  mSize+=src.Size();
262  int end = Size();
263  InitializeCopyDataBlock(start,end,0,src.mpData);
264  return *this;
265  }
266 
267  void Apply( T (*f)(T) )
268  {
269  int i;
270  for (i=0; i<mSize; i++)
271  (*this)[i] = f( (*this)[i] );
272  }
273 
274  void Apply( T (*f)(T,int),int parameter )
275  {
276  int i;
277  for (i=0; i<mSize; i++)
278  (*this)[i] = f( (*this)[i], parameter );
279  }
280 
281  void StoreOn(Storage & storage) const
282  {
283  StoreBufferOn((typename TypeInfo<T>::StorableAsLeaf *)NULL, mpData, storage);
284  }
285  void LoadFrom(Storage & storage)
286  {
287  LoadBufferFrom((typename TypeInfo<T>::StorableAsLeaf *)NULL, mpData, storage);
288  }
289 
290  // Error messages, to ease tests a little while we decide
291  // about error codes.
292  static const char *msgSetSizeOutOfRange;
293  static const char *msgIndexOutOfRange;
294  static const char *msgInsertOutOfRange;
295  static const char *msgDeleteOutOfRange;
296 
297 private:
298  inline void ResizeDataBuffer(int new_size);
299  inline void DestroyDataBuffer(void);
300  inline void InsertElemInDataBuffer(int position);
301  inline void DeleteElemInDataBuffer(int position);
302  inline void InitializeElement(int position);
303  inline void InitializeDataBlock(int first, int last);
304  inline void UninitializeDataBlock(int first, int last);
305  inline void CopyDataBlock(int first, int last, const T* src);
306  inline void InitializeCopyDataBlock(int first, int last, const T* src);
307  inline void InitializeCopyDataBlock(int first, int last, int src_first, const T* src);
308 
309  void StoreBufferOn(StaticFalse* asLeave, const Component * polymorphicSelector, Storage & storage) const
310  {
311  if (mSize<=0) return;
312  const char* className = mpData[0].GetClassName();
313  const char* label = className? className : "Element";
314  for (int i=0; i<mSize; i++)
315  {
316  XMLComponentAdapter adapter(mpData[i], label, true);
317  storage.Store(adapter);
318  }
319  }
320  void StoreBufferOn(StaticTrue* asLeave, const void * polymorphicSelector, Storage & storage) const
321  {
322  XMLAdapter<unsigned> sizeAdapter(Size(),"size");
323  storage.Store(sizeAdapter);
324  XMLArrayAdapter<T> adapter(mpData,mSize);
325  storage.Store(adapter);
326  }
327  void StoreBufferOn(StaticFalse* asLeave, const void * polymorphicSelector, Storage & storage) const
328  {
329  CLAM_ASSERT(false,
330  "Trying to Store an object that is not neither a streamable nor a Component");
331  }
332  void LoadBufferFrom(StaticFalse* asLeave, Component * polymorphicSelector, Storage & storage)
333  {
334  const char* label = 0;
335  while (true)
336  {
337  T elem;
338  if (!label)
339  {
340  label = elem.GetClassName();
341  if (!label)
342  label = "Element";
343  }
344  XMLComponentAdapter adapter(elem, label, true);
345  if (!storage.Load(adapter)) return;
346  AddElem(elem);
347  }
348  }
349  void LoadBufferFrom(StaticTrue* asLeave, void * polymorphicSelector, Storage & storage)
350  {
351  unsigned size;
352  XMLAdapter<unsigned> sizeAdapter(size,"size");
353  if (storage.Load(sizeAdapter))
354  {
355  Resize(size);
356  SetSize(size);
357  XMLArrayAdapter<T> adapter(mpData,mSize);
358  storage.Load(adapter);
359  // TODO: if false, then insert an error on the storage
360  return;
361  }
362 
363  while (true) {
364  T elem;
365  XMLAdapter<T> adapter(elem);
366  if ( ! storage.Load(adapter)) return;
367  AddElem(elem);
368  }
369  }
370  void LoadBufferFrom(StaticFalse* asLeave, void * polymorphicSelector, Storage & storage)
371  {
372  CLAM_ASSERT(false,
373  "Trying to Store an object that is not neither a streamable nor a Component");
374  }
375 /*
376  void StoreMemberOn(StaticTrue* asLeave, void * item, Storage & storage) const {
377  XMLAdapter<T> adapter(*(T*)item);
378  storage.Store(adapter);
379  }
380  void StoreMemberOn(StaticFalse* asLeave, Component * item, Storage & storage) const {
381  const char* className = item->GetClassName();
382  const char* label = className? className : "Element";
383  XMLComponentAdapter adapter(*item, label, true);
384  storage.Store(adapter);
385  }
386  bool StoreMemberOn(StaticFalse* asLeave, void * item, Storage & storage) {
387  CLAM_ASSERT(false, "Trying to Store an object that is not neither a streamable nor a Component");
388  return false;
389  }
390 */
391  bool LoadMemberFrom(StaticTrue* asLeave, void * item, Storage & storage) {
392  XMLAdapter<T> adapter(*(T*)item);
393  return storage.Load(adapter);
394  }
395  bool LoadMemberFrom(StaticFalse* asLeave, Component * item, Storage & storage) {
396  const char* className = (item->GetClassName());
397  const char* label = className? className : "Element";
398  XMLComponentAdapter adapter(*item, label, true);
399  return storage.Load(adapter);
400  }
401  bool LoadMemberFrom(StaticFalse* asLeave, void * item, Storage & storage) {
402  CLAM_ASSERT(false, "Trying to Load an object that is not neither a streamable nor a Component");
403  return false;
404  }
405 
406 };
407 
408 // Method implementations
409 
410 
411 template<class T>
412 void Array<T>::GiveChunk(int pos, int size, Array<T>& a) const
413 {
414  CLAM_ASSERT(pos + size <= mSize,
415  "Array::GiveChunk(): Chunk out of bounds.");
416  a.SetPtr(&mpData[pos],size);
417 }
418 
419 template<class T>
420 void Array<T>::CopyChunk(int pos, int size, Array<T>& a) const
421 {
422  int last=pos+size;
423  CLAM_ASSERT(last <= mSize,
424  "Array::CopyChunk(): Chunk out of bounds.");
425  CLAM_ASSERT(size <= a.mSize,
426  "Array::CopyChunk(): destination array does not have enough memory");
427  for (int i=pos;i<last;i++)
428  a.mpData[i-pos]=mpData[i];
429 }
430 
431 template<class T>
432 void Array<T>::InitializeElement(int i)
433 {
434  new (&mpData[i]) T();
435 }
436 
437 template<class T>
438 void Array<T>::InitializeDataBlock(int first, int last)
439 {
440  int i;
441  for (i = first; i < last; i++)
442  InitializeElement(i);
443 }
444 
445 template<class T>
446 void Array<T>::UninitializeDataBlock(int first, int last)
447 {
448  int i;
449  for (i = first; i < last; i++)
450  (&mpData[i])->~T();
451 }
452 
453 template<class T>
454 void Array<T>::CopyDataBlock(int first, int last, const T* src)
455 {
456  int i;
457  for (i=first; i<last ;i++)
458  mpData[i]=src[i];
459 }
460 
461 template<class T>
462 void Array<T>::InitializeCopyDataBlock(int first, int last, const T* src)
463 {
464  int i;
465  for (i=first; i<last; i++)
466  new(&mpData[i]) T(src[i]);
467 }
468 
469 template<class T>
470 void Array<T>::InitializeCopyDataBlock(int first, int last, int src_first, const T* src)
471 {
472  int i, j = src_first;
473  for (i=first; i<last; i++)
474  new (&mpData[i]) T(src[j++]);
475 }
476 
477 
478 template<class T>
479 void Array<T>::DestroyDataBuffer()
480 {
481  if (OwnsMemory())
482  {
483  UninitializeDataBlock(0,mSize);
484  free(mpData);
485  }
486  mpData=NULL;
487 }
488 
490 template<class T>
491 void Array<T>::ResizeDataBuffer(int new_size)
492 {
493  if (new_size == mAllocSize)
494  return;
495  T* old_data = mpData;
496  mpData = (T*) malloc(new_size*sizeof(T));
497  if (!old_data) return;
498  int elems = new_size;
499  if (mSize < elems)
500  elems = mSize;
501  InitializeCopyDataBlock(0,elems,old_data);
502  for (int i=0; i<mSize; i++)
503  (&old_data[i])->~T();
504  free(old_data);
505 }
506 
514 template<class T>
515 void Array<T>::InsertElemInDataBuffer(int position)
516 {
517  if (mSize>0)
518  new(&mpData[mSize]) T(mpData[mSize-1]);
519  for (int i=mSize-1; i>position; i--)
520  mpData[i] = mpData[i-1];
521  (&mpData[position])->~T();
522 }
523 
530 template<class T>
531 void Array<T>::DeleteElemInDataBuffer(int position)
532 {
533  for (int i=position; i<mSize-1; i++)
534  mpData[i] = mpData[i+1];
535  (&mpData[mSize-1])->~T();
536 }
537 
538 
539 template <class T> inline Array<T> operator + (
540  const Array<T>& a,const Array<T>& b)
541 {
542  Array<T> ret = a;
543  ret += b;
544  return ret;
545 }
546 
547 template <class T> inline bool operator == (
548  const Array<T>& a,const Array<T>& b)
549 {
550  if (a.Size()!=b.Size()) return false;
551  for (int i=0;i<a.Size();i++)
552  {
553  if (a[i]!=b[i]) return false;
554  }
555  return true;
556 }
557 
558 
559 
561 
562 template<class T>
563 const char* Array<T>::msgSetSizeOutOfRange =
564 "Array::SetSize(): Argument larger than allocated size\n"
565 "You can probably fix this calling Resize() befor SetSize().";
566 
567 template<class T>
568 const char* Array<T>::msgIndexOutOfRange =
569 "Array::operator[]: Index out of range\n"
570 "This may happen if you forgot to call SetSize(...) in your code.\n"
571 "This is now needed. Just calling Resize() is not enough any more.";
572 
573 template<class T>
574 const char* Array<T>::msgInsertOutOfRange =
575 "Array::InsertElem: Index out of range";
576 
577 template<class T>
578 const char* Array<T>::msgDeleteOutOfRange =
579 "Array::DeleteElem: Index out of range";
580 
581 }
582 
583 #endif//_Array_
584