IT++ Logo Newcom Logo

circular_buffer.h

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

Generated on Sat Aug 25 23:37:26 2007 for IT++ by Doxygen 1.5.2