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 
00091   template<class T>
00092   class Circular_Buffer {
00093   public:
00095     Circular_Buffer();
00096 
00098     Circular_Buffer(int n);
00099 
00101     Circular_Buffer(const Circular_Buffer<T> &s);
00102 
00104     virtual ~Circular_Buffer();
00105 
00107     void put(const T& in);
00108 
00110     void put(const Vec<T>& in);
00111 
00113     void put(const Array<T>& in);
00114 
00116     void get(T& out);
00117 
00119     T get();
00120 
00122     void get(Vec<T>& out, const int N=-1);
00123 
00125     void get(Array<T>& out, const int N=-1);
00126 
00128     void peek(T& out) const;
00129 
00131     T peek() const;
00132 
00134     void peek(const int index, T& out) const;
00135 
00137     void peek(Vec<T>& out, const int N=-1) const;
00138 
00140     void peek(const ivec& index, Vec<T>& out) const;
00141 
00143     void peek(Array<T>& out, const int N=-1) const;
00144 
00146     void peek(const ivec& index, Array<T>& out) const;
00147 
00149     void peek_reverse(T& out) const;
00150 
00152     T peek_reverse() const;
00153 
00155     void peek_reverse(Vec<T>& out, const int N=-1) const;
00156 
00158     void peek_reverse(Array<T>& out, const int N=-1) const;
00159 
00161     void clear();
00162 
00164     void operator=(const Circular_Buffer<T> &s);
00165 
00167     int size() const { return _ndata; }
00168 
00170     int nrof_elements() const { return _rw_dist; }
00171 
00173     void set_size(int n, bool copy=false);
00174 
00175   private:
00176 
00177     int _write;
00178     int _read;
00179     int _ndata;
00180     int _rw_dist;
00181     T *_data;
00182 
00183     void alloc(int n);
00184     void free();
00185 
00186   };
00187 
00188   // --------------------------- Implementation starts here ----------------------------------
00189 
00190   template<class T>
00191     Circular_Buffer<T>::Circular_Buffer()
00192     {
00193       _data    = 0;
00194       _ndata   = 0;
00195       _rw_dist = 0;
00196       _read    = 0;
00197       _write   = 0;
00198     }
00199 
00200   template<class T>
00201     Circular_Buffer<T>::Circular_Buffer(int n)
00202     {
00203       alloc(n);
00204       _read    = 0;
00205       _write   = 0;
00206       _rw_dist = 0;
00207     }
00208 
00209   template<class T>
00210     Circular_Buffer<T>::Circular_Buffer(const Circular_Buffer<T> &cb)
00211     {
00212       _data    = NULL;
00213       _ndata   = 0;
00214       _read    = cb._read;
00215       _write   = cb._write;
00216       _rw_dist = cb._rw_dist;
00217 
00218       alloc(cb._ndata);
00219       for (int i=0; i<cb._ndata; i++) { _data[i] = cb._data[i]; }
00220     }
00221 
00222   template<class T>
00223     Circular_Buffer<T>::~Circular_Buffer()
00224     {
00225       free();
00226     }
00227 
00228   template <class T>
00229     void Circular_Buffer<T>::get(T& out)
00230     {
00231       it_assert_debug(_rw_dist>0,"Buffer empty. No data left to read from the buffer.");
00232       out=_data[_read];
00233       _read++;
00234       _rw_dist--;
00235 
00236       if (_read==_ndata) { _read=0; }
00237     }
00238 
00239   template <class T>
00240     T Circular_Buffer<T>::get()
00241     {
00242       T out;
00243 
00244       get(out);
00245       return out;
00246     }
00247 
00248   template <class T>
00249     void Circular_Buffer<T>::get(Vec<T>& out, const int N)
00250     {
00251       int N_out;
00252 
00253       if (N==-1)
00254   N_out=_rw_dist;
00255       else
00256   N_out=N;
00257 
00258       out.set_size(N_out);
00259 
00260       for (int i=0;i<N_out;i++)
00261   {
00262     it_assert_debug(_rw_dist>0,"Buffer empty. No data left to read from the buffer.");
00263     out(i)=_data[_read];
00264     _read++;
00265     _rw_dist--;
00266 
00267     if (_read==_ndata)
00268       _read=0;
00269   }
00270     }
00271 
00272   template <class T>
00273     void Circular_Buffer<T>::get(Array<T>& out, const int N)
00274     {
00275       int N_out;
00276 
00277       if (N==-1)
00278   N_out=_rw_dist;
00279       else
00280   N_out=N;
00281 
00282       out.set_size(N_out);
00283 
00284       for (int i=0;i<N_out;i++)
00285   {
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   {
00335     out(i)=_data[read_tmp];
00336     read_tmp++;
00337     if (read_tmp==_ndata)
00338       read_tmp=0;
00339   }
00340     }
00341 
00342   template <class T>
00343     void Circular_Buffer<T>::peek(const ivec& index, Vec<T>& out) const
00344     {
00345       out.set_size(index.size());
00346 
00347       for (int i=0;i<index.size();i++)
00348   {
00349     it_assert_debug(_rw_dist>=index(i) && index(i)>=0,"Attempted to peek at an element, whose index exceeds the number of buffered elements.");
00350     out(i)=_data[(_read+index(i))%_ndata];
00351   }
00352     }
00353 
00354   template <class T>
00355     void Circular_Buffer<T>::peek(Array<T>& out, const int N) const
00356     {
00357       int N_out;
00358       int read_tmp=_read;
00359 
00360       if (N==-1)
00361   N_out=_rw_dist;
00362       else
00363   N_out=N;
00364 
00365       it_assert_debug(_rw_dist>=N_out,"Attempted to peek at more elements than there are stored in the buffer.");
00366       out.set_size(N_out);
00367 
00368       for (int i=0;i<N_out;i++)
00369   {
00370     out(i)=_data[read_tmp];
00371     read_tmp++;
00372     if (read_tmp==_ndata)
00373       read_tmp=0;
00374   }
00375     }
00376 
00377   template <class T>
00378     void Circular_Buffer<T>::peek(const ivec& index, Array<T>& out) const
00379     {
00380       out.set_size(index.size());
00381 
00382       for (int i=0;i<index.size();i++)
00383   {
00384     it_assert_debug(_rw_dist>=index(i) && index(i)>=0,"Attempted to peek at an element, whose index exceeds the number of buffered elements.");
00385     out(i)=_data[(_read+index(i))%_ndata];
00386   }
00387     }
00388 
00389   template <class T>
00390     void Circular_Buffer<T>::peek_reverse(T& out) const
00391     {
00392       int read_tmp;
00393 
00394       it_assert_debug(_rw_dist>0,"Attempted to peek at an empty buffer.");
00395 
00396       if (_write>0)
00397   read_tmp=_write-1;
00398       else
00399   read_tmp=_ndata-1;
00400 
00401       out=_data[read_tmp];
00402     }
00403 
00404   template <class T>
00405     T Circular_Buffer<T>::peek_reverse() const
00406     {
00407       T out;
00408 
00409       peek_reverse(out);
00410       return out;
00411     }
00412 
00413   template <class T>
00414     void Circular_Buffer<T>::peek_reverse(Vec<T>& out, const int N) const
00415     {
00416       int N_out;
00417       int read_tmp;
00418 
00419       if (N==-1)
00420   N_out=_rw_dist;
00421       else
00422   N_out=N;
00423 
00424       it_assert_debug(_rw_dist>=N_out,"Attempted to peek at more elements than there are stored in the buffer.");
00425       out.set_size(N_out);
00426 
00427       if (_write>0)
00428   read_tmp=_write-1;
00429       else
00430   read_tmp=_ndata-1;
00431 
00432       for (int i=0;i<N_out;i++)
00433   {
00434     out(i)=_data[read_tmp];
00435     read_tmp--;
00436     if (read_tmp<0)
00437       read_tmp=_ndata-1;
00438   }
00439     }
00440 
00441   template <class T>
00442     void Circular_Buffer<T>::peek_reverse(Array<T>& out, const int N) const
00443     {
00444       int N_out;
00445       int read_tmp;
00446 
00447       if (N==-1)
00448   N_out=_rw_dist;
00449       else
00450   N_out=N;
00451 
00452       it_assert_debug(_rw_dist>=N_out,"Attempted to peek at more elements than there are stored in the buffer.");
00453       out.set_size(N_out);
00454 
00455       if (_write>0)
00456   read_tmp=_write-1;
00457       else
00458   read_tmp=_ndata-1;
00459 
00460       for (int i=0;i<N_out;i++)
00461   {
00462     out(i)=_data[read_tmp];
00463     read_tmp--;
00464     if (read_tmp<0)
00465       read_tmp=_ndata-1;
00466   }
00467     }
00468 
00469   template <class T>
00470     void Circular_Buffer<T>::put(const T& in)
00471     {
00472       //Remove the oldest element of the buffer if the buffer is full
00473       if (_rw_dist>=_ndata)
00474   {
00475     T dummy;
00476     get(dummy);
00477   }
00478 
00479       //Write data to the buffer and move the pointer to the next buffer slot
00480       _data[_write]=in;
00481       _write++;
00482       _rw_dist++;
00483 
00484       //Check if the pointer in the circular buffer should go back to zero
00485       if (_write>=_ndata)
00486   _write=0;
00487 
00488     }
00489 
00490   template <class T>
00491     void Circular_Buffer<T>::put(const Vec<T>& in)
00492     {
00493       for (int i=0;i<in.size();i++)
00494   {
00495     //Remove the oldest element of the buffer if the buffer is full
00496     if (_rw_dist>=_ndata)
00497       {
00498         T dummy;
00499         get(dummy);
00500       }
00501 
00502     //Write data to the buffer and move the pointer to the next buffer slot
00503     _data[_write]=in(i);
00504     _write++;
00505     _rw_dist++;
00506 
00507     //Check if the pointer in the circular buffer should go back to zero
00508     if (_write>=_ndata)
00509       _write=0;
00510   }
00511 
00512     }
00513 
00514   template <class T>
00515     void Circular_Buffer<T>::put(const Array<T>& in)
00516     {
00517       for (int i=0;i<in.size();i++)
00518   {
00519     //Remove the oldest element of the buffer if the buffer is full
00520     if (_rw_dist>=_ndata)
00521       {
00522         T dummy;
00523         get(dummy);
00524       }
00525 
00526     //Write data to the buffer and move the pointer to the next buffer slot
00527     _data[_write]=in(i);
00528     _write++;
00529     _rw_dist++;
00530 
00531     //Check if the pointer in the circular buffer should go back to zero
00532     if (_write>=_ndata)
00533       _write=0;
00534   }
00535     }
00536 
00537   template <class T>
00538     void Circular_Buffer<T>::clear()
00539     {
00540       _write   = 0;
00541       _read    = 0;
00542       _rw_dist = 0;
00543     }
00544 
00545   template<class T>
00546     void Circular_Buffer<T>::alloc(int n)
00547     {
00548       if (n == 0) {
00549   _ndata = 0;
00550   _data  = NULL;
00551       }
00552       else if (n>0) {
00553   _ndata = n;
00554   _data = new T[_ndata];
00555   it_assert(_data!=0, "Out of memory in Circular_Buffer::alloc");
00556       }
00557       else {
00558   it_error("Circular_Buffer<T>::alloc(int n): n must be positive");
00559       }
00560     }
00561 
00562   template<class T>
00563     void Circular_Buffer<T>::free()
00564     {
00565       delete [] _data;
00566 
00567       _data    = NULL;
00568       _ndata   = 0;
00569       _write   = 0;
00570       _read    = 0;
00571       _rw_dist = 0;
00572     }
00573 
00574   template<class T>
00575     void Circular_Buffer<T>::operator=(const Circular_Buffer<T> &s)
00576     {
00577       set_size(s._ndata);
00578       for (int i=0; i<_ndata; i++)
00579   _data[i] = s._data[i];
00580       _read=s._read;
00581       _write=s._write;
00582       _rw_dist=_write-_read;
00583     }
00584 
00585   template<class T>
00586     void Circular_Buffer<T>::set_size(int sz, bool copy)
00587     {
00588       int i, min_nrof_elem;
00589       //T *tmp;
00590       Vec<T> tmp;
00591 
00592       if (_ndata == sz)
00593   return;
00594 
00595       if (copy)
00596   {
00597     peek_reverse(tmp,-1);
00598     min_nrof_elem = _rw_dist < sz ? _rw_dist : sz;
00599     alloc(sz);
00600     clear();
00601     for (i=0; i<min_nrof_elem; i++)
00602       put(tmp(min_nrof_elem-1-i));
00603   }
00604       else
00605   {
00606     free();
00607     alloc(sz);
00608   }
00609 
00610       _ndata = sz;
00611     }
00612 
00613 } // namespace itpp
00614 
00615 #endif // #ifndef CIRCULAR_BUFFER_H
SourceForge Logo

Generated on Sun Sep 14 18:54:50 2008 for IT++ by Doxygen 1.5.6