CLAM-Development  1.4.0
CircularBuffer.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 _CircularBuffer_
23 #define _CircularBuffer_
24 
25 #include "Array.hxx"
26 #include "DataTypes.hxx"
27 #include "Err.hxx"
28 
29 namespace CLAM
30 {
31 
32 
46  template <class T> class CircularBuffer
47  {
48  protected:
53  TSize mWriteIndex; // XXX: might want these mutable and read-like methods declared const
54  TSize mReadIndex; // XXX: might want these mutable and read-like methods declared const
57 
58  public:
59 
67  {
68  mWriteIndex = 0;
69  mReadIndex = 0;
70  mReadSize = mWriteSize = 1;
73  SetBufferSize(0);
74  mLogicalSize = 0;
75  }
76 
82  CircularBuffer(TSize bufferSize) : mBuffer(bufferSize)
83  {
84  CLAM_ASSERT(bufferSize > 0, "CircularBuffer:CircularBuffer: BufferSize has to be larger than zero");
85  SetBufferSize(bufferSize);
86  mWriteIndex = 0;
87  mReadIndex = 0;
88  mReadSize = mWriteSize = 1;
91  mLogicalSize = 0;
92  }
93 
94  // Methods for setting up the buffer: -------------------------------------------
95 
100  {
101  return mBuffer.Size()-GetReadSize();
102  }
103 
109  void SetBufferSize(TSize size)
110  {
111  mBuffer.Resize(size+GetReadSize());
112  mBuffer.SetSize(size+GetReadSize());
113  InitPointers();
114  }
115 
121  {
122  return mWriteIndex;
123  }
124 
130  {
131  return mReadIndex;
132  }
133 
140  {
141  return mInitialReadOffset;
142  }
143 
151  {
152  CLAM_ASSERT((size >= 0)&&(size < GetBufferSize()-1),
153  "CircularBuffer:SetInitialReadOffset: InitialReadOffset has to be larger than zero");
154  mInitialReadOffset = size;
155  }
156 
163  {
164  return mInitialWriteOffset;
165  }
166 
174  {
175  CLAM_ASSERT((size >= 0)&&(size < GetBufferSize()-1),
176  "CircularBuffer:SetInitialWriteOffset: InitialWriteOffset has to be larger than zero");
177  mInitialWriteOffset = size;
178  }
179 
180  // Methods for data acces: ------------------------------------------------------
181 
187  void Init()
188  {
189  SetBufferToZero();
190  InitPointers();
191  }
192 
197  {
198  T *pBuffer;
199  pBuffer = mBuffer.GetPtr();
200  memset(pBuffer, 0, GetBufferSize()*sizeof(T));
201  }
202 
208  {
209  if(mInitialReadOffset < 0)
211  else
213  if(mInitialWriteOffset < 0)
215  else
217  mLogicalSize=0;
218  }
219 
220  // Methods for reading and writing: ---------------------------------------------
221 
226  void Read(T& element)
227  {
228  element = mBuffer[mReadIndex];
230  }
231 
232 
233  void NonCopyRead(Array<T>& buffer)
234  {
235  TSize limit;
236  if((limit=mReadIndex+mReadSize)>GetBufferSize())
237  {
238  //will have to use phantom zone
239  memcpy(mBuffer.GetPtr()+GetBufferSize(),mBuffer.GetPtr(),mReadSize*sizeof(T));
240  }
241  buffer.SetPtr(mBuffer.GetPtr()+mReadIndex,mReadSize);
243 
244 
245  }
246 
253  void Read(T* buffer)
254  {
255  TSize limit;
256  if((limit=mReadIndex+mReadSize)>GetBufferSize())
257  {
258  TSize secondHalf=limit%GetBufferSize();
259  TSize firstHalf=mReadSize-secondHalf;
260  memcpy(buffer,mBuffer.GetPtr()+mReadIndex,firstHalf*sizeof(T));
261  memcpy(buffer+firstHalf,mBuffer.GetPtr(),secondHalf*sizeof(T));
262  }
263  else
264  {
265  memcpy(buffer,mBuffer.GetPtr()+mReadIndex,mReadSize*sizeof(T));
266  }
267 
269  }
270 
280  void Read(Array<T>& in, TSize offset = 0) // XXX: maybe call in, out instead?
281  {
282  CLAM_ASSERT(GetReadSize() <= in.Size()+offset, "Error, input buffer is not large enough"); // XXX: maybe call the input buffer the output buffer?
283 
284 #ifdef CLAM_HIGH_OPTIMIZATIONS
285  Read(in.GetPtr()+offset);
286 #else
287  for(int i=0;i<mReadSize;i++)
288  Read(in[i+offset]);
289 #endif
290  }
291 
295  void Write(const T& element)
296  {
297  mBuffer[mWriteIndex] = element;
299  }
300 
306  void Write(const T* buffer)
307  {
308  TSize limit;
309  if((limit=mWriteIndex+mWriteSize)>GetBufferSize())
310  {
311  TSize secondHalf=limit%GetBufferSize();
312  TSize firstHalf=mWriteSize-secondHalf;
313  memcpy(mBuffer.GetPtr()+mWriteIndex,buffer,firstHalf*sizeof(T));
314  memcpy(mBuffer.GetPtr(),buffer+firstHalf,secondHalf*sizeof(T));
315  }
316  else
317  {
318  memcpy(mBuffer.GetPtr()+mWriteIndex,buffer,mWriteSize*sizeof(T));
319  }
320 
322  }
323 
331  void Write(const Array<T>& in, TSize offset = 0)
332  {
333  CLAM_ASSERT(GetWriteSize()<=in.Size()+offset,"Error, input buffer is not large enough");
334 #ifdef CLAM_HIGH_OPTIMIZATIONS
335  Write(in.GetPtr()+offset);
336 #else
337  for(int i=0;i<mWriteSize;i++)
338  Write(in[i+offset]);
339 #endif
340  }
341 
347  void Add(const T& elem)
348  {
349  mBuffer[mWriteIndex] += elem;
351  }
352 
360  void Add(const Array<T>& in, TSize offset = 0)
361  {
362  CLAM_ASSERT(GetWriteSize()<=in.Size()+offset,"Error, input buffer is not large enough");
363  for(int i=0;i<mWriteSize;i++)
364  Add(in[i+offset]);
365  // XXX: might also want a CLAM_HIGH_OPTIMIZATIONS version of this method...
366  }
367 
372  void IncreaseReadIndex(TSize step = 1)
373  {
374  mReadIndex += step;
376  mLogicalSize-=step;
377  CLAM_ASSERT(mLogicalSize>=0,"Error:Read Index surpassed Write Index");
378  }
379 
384  void IncreaseWriteIndex(TSize step = 1)
385  {
386  // XXX: might want to assert that step > 0
387  mWriteIndex += step;
389  mLogicalSize+=step;
390  CLAM_ASSERT(mLogicalSize<=GetBufferSize(),"Error:Write Index surpassed Read Index");
391  }
392 
397  void DecreaseReadIndex(TSize step = 1)
398  {
399  // XXX: might want to assert that step > 0
400  mReadIndex -= step;
403  mLogicalSize+=step;
404  CLAM_ASSERT(mLogicalSize<=GetBufferSize(),"Error:Write Index surpassed Read Index");
405  }
406 
411  void DecreaseWriteIndex(TSize step = 1)
412  {
413  // XXX: might want to assert that step > 0
414  mWriteIndex -= step;
417  mLogicalSize-=step;
418  CLAM_ASSERT(mLogicalSize>=0,"Error:Read Index surpassed Write Index");
419  }
420 
426  T& GetPtrToElement(int absPos)
427  {
428  int index = absPos%GetBufferSize(); // XXX: unnecessary copy.
429 
430  return mBuffer[index];
431  }
432 
433  // Getters and setters: ---------------------------------------------------------
434 
441  {
442  return mReadSize;
443  }
444 
451  {
452  return mWriteSize;
453  }
454 
459  void SetReadSize(TSize size)
460  {
461  CLAM_ASSERT(size>=0&&size<=GetBufferSize(),"AudioCircularBuffer:SetReadSize: ReadSize has to be larger than zero");
462  TSize previousBufferSize=GetBufferSize();
463  mReadSize = size;
464  SetBufferSize(previousBufferSize);
465  }
466 
471  void SetWriteSize(TSize size)
472  {
473  CLAM_ASSERT(size>=0&&size<=GetBufferSize(),"AudioCircularBuffer:SetWriteSize: WriteSize has to be larger than zero");
474  mWriteSize = size;
475  }
476  };
477 
478 
479 
480 }; //end of namespace
481 
482 #endif //_CircularBuffer_
483