IT++ Logo

circular_buffer.h

Go to the documentation of this file.
00001 
00036 #ifndef CIRCULAR_BUFFER_H
00037 #define CIRCULAR_BUFFER_H
00038 
00039 #include <itpp/base/vec.h>
00040 #include <itpp/base/array.h>
00041 
00042 
00043 namespace itpp
00044 {
00045 
00092 template<class T>
00093 class Circular_Buffer
00094 {
00095 public:
00097   Circular_Buffer();
00098 
00100   Circular_Buffer(int n);
00101 
00103   Circular_Buffer(const Circular_Buffer<T> &s);
00104 
00106   virtual ~Circular_Buffer();
00107 
00109   void put(const T& in);
00110 
00112   void put(const Vec<T>& in);
00113 
00115   void put(const Array<T>& in);
00116 
00118   void get(T& out);
00119 
00121   T get();
00122 
00124   void get(Vec<T>& out, const int N = -1);
00125 
00127   void get(Array<T>& out, const int N = -1);
00128 
00130   void peek(T& out) const;
00131 
00133   T peek() const;
00134 
00136   void peek(const int index, T& out) const;
00137 
00139   void peek(Vec<T>& out, const int N = -1) const;
00140 
00142   void peek(const ivec& index, Vec<T>& out) const;
00143 
00145   void peek(Array<T>& out, const int N = -1) const;
00146 
00148   void peek(const ivec& index, Array<T>& out) const;
00149 
00151   void peek_reverse(T& out) const;
00152 
00154   T peek_reverse() const;
00155 
00157   void peek_reverse(Vec<T>& out, const int N = -1) const;
00158 
00160   void peek_reverse(Array<T>& out, const int N = -1) const;
00161 
00163   void clear();
00164 
00166   void operator=(const Circular_Buffer<T> &s);
00167 
00169   int size() const { return _ndata; }
00170 
00172   int nrof_elements() const { return _rw_dist; }
00173 
00175   void set_size(int n, bool copy = false);
00176 
00177 private:
00178 
00179   int _write;
00180   int _read;
00181   int _ndata;
00182   int _rw_dist;
00183   T *_data;
00184 
00185   void alloc(int n);
00186   void free();
00187 
00188 };
00189 
00190 // --------------------------- Implementation starts here ----------------------------------
00191 
00192 template<class T>
00193 Circular_Buffer<T>::Circular_Buffer()
00194 {
00195   _data    = 0;
00196   _ndata   = 0;
00197   _rw_dist = 0;
00198   _read    = 0;
00199   _write   = 0;
00200 }
00201 
00202 template<class T>
00203 Circular_Buffer<T>::Circular_Buffer(int n)
00204 {
00205   alloc(n);
00206   _read    = 0;
00207   _write   = 0;
00208   _rw_dist = 0;
00209 }
00210 
00211 template<class T>
00212 Circular_Buffer<T>::Circular_Buffer(const Circular_Buffer<T> &cb)
00213 {
00214   _data    = NULL;
00215   _ndata   = 0;
00216   _read    = cb._read;
00217   _write   = cb._write;
00218   _rw_dist = cb._rw_dist;
00219 
00220   alloc(cb._ndata);
00221   for (int i = 0; i < cb._ndata; i++) { _data[i] = cb._data[i]; }
00222 }
00223 
00224 template<class T>
00225 Circular_Buffer<T>::~Circular_Buffer()
00226 {
00227   free();
00228 }
00229 
00230 template <class T>
00231 void Circular_Buffer<T>::get(T& out)
00232 {
00233   it_assert_debug(_rw_dist > 0, "Buffer empty. No data left to read from the buffer.");
00234   out = _data[_read];
00235   _read++;
00236   _rw_dist--;
00237 
00238   if (_read == _ndata) { _read = 0; }
00239 }
00240 
00241 template <class T>
00242 T Circular_Buffer<T>::get()
00243 {
00244   T out;
00245 
00246   get(out);
00247   return out;
00248 }
00249 
00250 template <class T>
00251 void Circular_Buffer<T>::get(Vec<T>& out, const int N)
00252 {
00253   int N_out;
00254 
00255   if (N == -1)
00256     N_out = _rw_dist;
00257   else
00258     N_out = N;
00259 
00260   out.set_size(N_out);
00261 
00262   for (int i = 0;i < N_out;i++) {
00263     it_assert_debug(_rw_dist > 0, "Buffer empty. No data left to read from the buffer.");
00264     out(i) = _data[_read];
00265     _read++;
00266     _rw_dist--;
00267 
00268     if (_read == _ndata)
00269       _read = 0;
00270   }
00271 }
00272 
00273 template <class T>
00274 void Circular_Buffer<T>::get(Array<T>& out, const int N)
00275 {
00276   int N_out;
00277 
00278   if (N == -1)
00279     N_out = _rw_dist;
00280   else
00281     N_out = N;
00282 
00283   out.set_size(N_out);
00284 
00285   for (int i = 0;i < N_out;i++) {
00286     it_assert_debug(_rw_dist > 0, "Buffer empty. No data left to read from the buffer.");
00287     out(i) = _data[_read];
00288     _read++;
00289     _rw_dist--;
00290 
00291     if (_read == _ndata)
00292       _read = 0;
00293   }
00294 }
00295 
00296 template <class T>
00297 void Circular_Buffer<T>::peek(T& out) const
00298 {
00299   it_assert_debug(_rw_dist > 0, "Attempted to peek at an empty buffer.");
00300   out = _data[_read];
00301 }
00302 
00303 template <class T>
00304 T Circular_Buffer<T>::peek() const
00305 {
00306   T out;
00307 
00308   peek(out);
00309   return out;
00310 }
00311 
00312 template <class T>
00313 void Circular_Buffer<T>::peek(const int index, T& out) const
00314 {
00315   it_assert_debug(_rw_dist > index && index >= 0, "The index exceeds the number of elements stored in the buffer.");
00316   out = _data[(_read+index)%_ndata];
00317 }
00318 
00319 template <class T>
00320 void Circular_Buffer<T>::peek(Vec<T>& out, const int N) const
00321 {
00322   int N_out;
00323   int read_tmp = _read;
00324 
00325   if (N == -1)
00326     N_out = _rw_dist;
00327   else
00328     N_out = N;
00329 
00330   it_assert_debug(_rw_dist >= N_out, "Attempted to peek at more elements than there are stored in the buffer.");
00331   out.set_size(N_out);
00332 
00333   for (int i = 0;i < N_out;i++) {
00334     out(i) = _data[read_tmp];
00335     read_tmp++;
00336     if (read_tmp == _ndata)
00337       read_tmp = 0;
00338   }
00339 }
00340 
00341 template <class T>
00342 void Circular_Buffer<T>::peek(const ivec& index, Vec<T>& out) const
00343 {
00344   out.set_size(index.size());
00345 
00346   for (int i = 0;i < index.size();i++) {
00347     it_assert_debug(_rw_dist >= index(i) && index(i) >= 0, "Attempted to peek at an element, whose index exceeds the number of buffered elements.");
00348     out(i) = _data[(_read+index(i))%_ndata];
00349   }
00350 }
00351 
00352 template <class T>
00353 void Circular_Buffer<T>::peek(Array<T>& out, const int N) const
00354 {
00355   int N_out;
00356   int read_tmp = _read;
00357 
00358   if (N == -1)
00359     N_out = _rw_dist;
00360   else
00361     N_out = N;
00362 
00363   it_assert_debug(_rw_dist >= N_out, "Attempted to peek at more elements than there are stored in the buffer.");
00364   out.set_size(N_out);
00365 
00366   for (int i = 0;i < N_out;i++) {
00367     out(i) = _data[read_tmp];
00368     read_tmp++;
00369     if (read_tmp == _ndata)
00370       read_tmp = 0;
00371   }
00372 }
00373 
00374 template <class T>
00375 void Circular_Buffer<T>::peek(const ivec& index, Array<T>& out) const
00376 {
00377   out.set_size(index.size());
00378 
00379   for (int i = 0;i < index.size();i++) {
00380     it_assert_debug(_rw_dist >= index(i) && index(i) >= 0, "Attempted to peek at an element, whose index exceeds the number of buffered elements.");
00381     out(i) = _data[(_read+index(i))%_ndata];
00382   }
00383 }
00384 
00385 template <class T>
00386 void Circular_Buffer<T>::peek_reverse(T& out) const
00387 {
00388   int read_tmp;
00389 
00390   it_assert_debug(_rw_dist > 0, "Attempted to peek at an empty buffer.");
00391 
00392   if (_write > 0)
00393     read_tmp = _write - 1;
00394   else
00395     read_tmp = _ndata - 1;
00396 
00397   out = _data[read_tmp];
00398 }
00399 
00400 template <class T>
00401 T Circular_Buffer<T>::peek_reverse() const
00402 {
00403   T out;
00404 
00405   peek_reverse(out);
00406   return out;
00407 }
00408 
00409 template <class T>
00410 void Circular_Buffer<T>::peek_reverse(Vec<T>& out, const int N) const
00411 {
00412   int N_out;
00413   int read_tmp;
00414 
00415   if (N == -1)
00416     N_out = _rw_dist;
00417   else
00418     N_out = N;
00419 
00420   it_assert_debug(_rw_dist >= N_out, "Attempted to peek at more elements than there are stored in the buffer.");
00421   out.set_size(N_out);
00422 
00423   if (_write > 0)
00424     read_tmp = _write - 1;
00425   else
00426     read_tmp = _ndata - 1;
00427 
00428   for (int i = 0;i < N_out;i++) {
00429     out(i) = _data[read_tmp];
00430     read_tmp--;
00431     if (read_tmp < 0)
00432       read_tmp = _ndata - 1;
00433   }
00434 }
00435 
00436 template <class T>
00437 void Circular_Buffer<T>::peek_reverse(Array<T>& out, const int N) const
00438 {
00439   int N_out;
00440   int read_tmp;
00441 
00442   if (N == -1)
00443     N_out = _rw_dist;
00444   else
00445     N_out = N;
00446 
00447   it_assert_debug(_rw_dist >= N_out, "Attempted to peek at more elements than there are stored in the buffer.");
00448   out.set_size(N_out);
00449 
00450   if (_write > 0)
00451     read_tmp = _write - 1;
00452   else
00453     read_tmp = _ndata - 1;
00454 
00455   for (int i = 0;i < N_out;i++) {
00456     out(i) = _data[read_tmp];
00457     read_tmp--;
00458     if (read_tmp < 0)
00459       read_tmp = _ndata - 1;
00460   }
00461 }
00462 
00463 template <class T>
00464 void Circular_Buffer<T>::put(const T& in)
00465 {
00466   //Remove the oldest element of the buffer if the buffer is full
00467   if (_rw_dist >= _ndata) {
00468     T dummy;
00469     get(dummy);
00470   }
00471 
00472   //Write data to the buffer and move the pointer to the next buffer slot
00473   _data[_write] = in;
00474   _write++;
00475   _rw_dist++;
00476 
00477   //Check if the pointer in the circular buffer should go back to zero
00478   if (_write >= _ndata)
00479     _write = 0;
00480 
00481 }
00482 
00483 template <class T>
00484 void Circular_Buffer<T>::put(const Vec<T>& in)
00485 {
00486   for (int i = 0;i < in.size();i++) {
00487     //Remove the oldest element of the buffer if the buffer is full
00488     if (_rw_dist >= _ndata) {
00489       T dummy;
00490       get(dummy);
00491     }
00492 
00493     //Write data to the buffer and move the pointer to the next buffer slot
00494     _data[_write] = in(i);
00495     _write++;
00496     _rw_dist++;
00497 
00498     //Check if the pointer in the circular buffer should go back to zero
00499     if (_write >= _ndata)
00500       _write = 0;
00501   }
00502 
00503 }
00504 
00505 template <class T>
00506 void Circular_Buffer<T>::put(const Array<T>& in)
00507 {
00508   for (int i = 0;i < in.size();i++) {
00509     //Remove the oldest element of the buffer if the buffer is full
00510     if (_rw_dist >= _ndata) {
00511       T dummy;
00512       get(dummy);
00513     }
00514 
00515     //Write data to the buffer and move the pointer to the next buffer slot
00516     _data[_write] = in(i);
00517     _write++;
00518     _rw_dist++;
00519 
00520     //Check if the pointer in the circular buffer should go back to zero
00521     if (_write >= _ndata)
00522       _write = 0;
00523   }
00524 }
00525 
00526 template <class T>
00527 void Circular_Buffer<T>::clear()
00528 {
00529   _write   = 0;
00530   _read    = 0;
00531   _rw_dist = 0;
00532 }
00533 
00534 template<class T>
00535 void Circular_Buffer<T>::alloc(int n)
00536 {
00537   if (n == 0) {
00538     _ndata = 0;
00539     _data  = NULL;
00540   }
00541   else if (n > 0) {
00542     _ndata = n;
00543     _data = new T[_ndata];
00544     it_assert(_data != 0, "Out of memory in Circular_Buffer::alloc");
00545   }
00546   else {
00547     it_error("Circular_Buffer<T>::alloc(int n): n must be positive");
00548   }
00549 }
00550 
00551 template<class T>
00552 void Circular_Buffer<T>::free()
00553 {
00554   delete [] _data;
00555 
00556   _data    = NULL;
00557   _ndata   = 0;
00558   _write   = 0;
00559   _read    = 0;
00560   _rw_dist = 0;
00561 }
00562 
00563 template<class T>
00564 void Circular_Buffer<T>::operator=(const Circular_Buffer<T> &s)
00565 {
00566   set_size(s._ndata);
00567   for (int i = 0; i < _ndata; i++)
00568     _data[i] = s._data[i];
00569   _read = s._read;
00570   _write = s._write;
00571   _rw_dist = _write - _read;
00572 }
00573 
00574 template<class T>
00575 void Circular_Buffer<T>::set_size(int sz, bool copy)
00576 {
00577   int i, min_nrof_elem;
00578   //T *tmp;
00579   Vec<T> tmp;
00580 
00581   if (_ndata == sz)
00582     return;
00583 
00584   if (copy) {
00585     peek_reverse(tmp, -1);
00586     min_nrof_elem = _rw_dist < sz ? _rw_dist : sz;
00587     alloc(sz);
00588     clear();
00589     for (i = 0; i < min_nrof_elem; i++)
00590       put(tmp(min_nrof_elem - 1 - i));
00591   }
00592   else {
00593     free();
00594     alloc(sz);
00595   }
00596 
00597   _ndata = sz;
00598 }
00599 
00600 } // namespace itpp
00601 
00602 #endif // #ifndef CIRCULAR_BUFFER_H
SourceForge Logo

Generated on Thu Apr 23 20:04:03 2009 for IT++ by Doxygen 1.5.8