root/win32/itpp-4.0.1/itpp/base/circular_buffer.h @ 129

Revision 35, 14.8 kB (checked in by mido, 16 years ago)

zasadni zmeny ve /win32

Line 
1/*!
2 * \file
3 * \brief Circular_Buffer class (container)
4 * \author Tobias Tynderfeldt
5 *
6 * -------------------------------------------------------------------------
7 *
8 * IT++ - C++ library of mathematical, signal processing, speech processing,
9 *        and communications classes and functions
10 *
11 * Copyright (C) 1995-2007  (see AUTHORS file for a list of contributors)
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 *
27 * -------------------------------------------------------------------------
28 *
29 * This file is not separated into .h and .cpp files. The reason is
30 * to avoid problems with template initializations of this class.
31 * A \c Circular_Buffer<type> can contain any type and it is not
32 * possible to initialize and pre-compile all types that might be put
33 * into a \c Circular_Buffer.
34 */
35
36#ifndef CIRCULAR_BUFFER_H
37#define CIRCULAR_BUFFER_H
38
39#include <itpp/base/vec.h>
40#include <itpp/base/array.h>
41
42
43namespace itpp {
44
45  /*!
46    \brief General circular buffer class
47
48    This class is a general circular buffer class for arbitrary types.
49
50    For rarely used types you will need to instantiate the class by
51    \code
52    template class Circular_Buffer<type>;
53    \endcode
54
55    The following example shows how to define a Circular_Buffer of doubles:
56    \code
57    vec a = randn(3);
58    vec b = randn(8);
59    vec out_vec;
60    Array <double> out_array;
61
62    Circular_Buffer<double> cb1(10);
63
64    //Put the elements of a to the buffer
65    cb1.put(a);
66
67    //Vector output: Peek at the two oldest elements of the buffer (the two first extracted)
68    cb1.peek(out_vec,2);
69    cout << "peek(out_vec,2) = " << out_vec << ": display 2 first elements of the buffer, without affecting the content"  << endl;
70
71    //Vector output: Peek at all elements of the buffer in reverse order
72    cb1.peek_reverse(out_vec);
73    cout << "peek_reverse(out_vec,-1) = " << out_vec << ": display buffer, without affecting the content"  << endl;
74
75    //Array output: Peek at all elements of the buffer in reverse order
76    cb1.peek_reverse(out_array);
77    cout << "peek_reverse(out_array,-1) = " << out_array << ": display buffer, without affecting the content"  << endl;
78
79    //Put the elements of \c b to the buffer
80    cb1.put(b);
81
82    //Extract the oldest element of the buffer
83    cb1.get(out_vec,1);
84    cout << "get(out_vec,1) = " << out_vec << endl ;
85
86    //Extract all element of the buffer
87    cb1.get(out_vec);
88    cout << "get(out_vec) = " << out_vec << endl ;
89    \endcode
90  */
91  template<class T>
92  class Circular_Buffer {
93  public:
94    //! Default constructor
95    Circular_Buffer();
96
97    //! Create a Circular_Buffer of size \c n
98    Circular_Buffer(int n);
99
100    //! Create a copy of \c s
101    Circular_Buffer(const Circular_Buffer<T> &s);
102
103    //! Default destructor
104    virtual ~Circular_Buffer();
105
106    //! Write the element \a in to the buffer
107    void put(const T& in);
108
109    //! Write the vector of elements \a in to the circular buffer
110    void put(const Vec<T>& in);
111
112    //! Write the vector of elements \a in to the circular buffer
113    void put(const Array<T>& in);
114
115    //! Get the oldest element in the circular buffer
116    void get(T& out);
117
118    //! Get the oldest element in the circular buffer
119    T get();
120
121    //! Get the N oldest element in the circular buffer. \c N=-1 returns all elements in the buffer
122    void get(Vec<T>& out, const int N=-1);
123
124    //! Get the N oldest element in the circular buffer. \c N=-1 returns all elements in the buffer
125    void get(Array<T>& out, const int N=-1);
126
127    //! Peek at the oldest element in the circular buffer, without removing it.
128    void peek(T& out) const;
129
130    //! Peek at the oldest element in the circular buffer, without removing it.
131    T peek() const;
132
133    //! Peek at the element with index \a index in the circular buffer, without removing it.
134    void peek(const int index, T& out) const;
135
136    //! Peek at the N first elements of the circular buffer, without removing them. \c N=-1 peeks all elements in the buffer
137    void peek(Vec<T>& out, const int N=-1) const;
138
139    //! Peek at the elements with index \a index in the circular buffer, without removing them.
140    void peek(const ivec& index, Vec<T>& out) const;
141
142    //! Peek at the N first elements of the circular buffer, without removing them. \c N=-1 peeks all elements in the buffer
143    void peek(Array<T>& out, const int N=-1) const;
144
145    //! Peek at the elements with index \a index in the circular buffer, without removing them.
146    void peek(const ivec& index, Array<T>& out) const;
147
148    //! Peek at the latest element in the circular buffer, without removing it.
149    void peek_reverse(T& out) const;
150
151    //! Peek at the latest element in the circular buffer, without removing it.
152    T peek_reverse() const;
153
154    //! Peek at the N latest elements of the circular buffer in reverse order, without removing them. \c N=-1 returns all elements in the buffer
155    void peek_reverse(Vec<T>& out, const int N=-1) const;
156
157    //! Peek at the N latest elements of the circular buffer in reverse order, without removing them. \c N=-1 returns all elements in the buffer
158    void peek_reverse(Array<T>& out, const int N=-1) const;
159
160    //! Empty the circular buffer
161    void clear();
162
163    //! Assignment operator
164    void operator=(const Circular_Buffer<T> &s);
165
166    //! Returns the maximum number of data elements the circular buffer can store
167    int size() const { return _ndata; }
168
169    //! Returns the number of data elements currently stored in the circular buffer
170    int nrof_elements() const { return _rw_dist; }
171
172    //! Resizing a Circular_Buffer<T>.
173    void set_size(int n, bool copy=false);
174
175  private:
176
177    int _write;
178    int _read;
179    int _ndata;
180    int _rw_dist;
181    T *_data;
182
183    void alloc(int n);
184    void free();
185
186  };
187
188  // --------------------------- Implementation starts here ----------------------------------
189
190  template<class T>
191    Circular_Buffer<T>::Circular_Buffer()
192    {
193      _data    = 0;
194      _ndata   = 0;
195      _rw_dist = 0;
196      _read    = 0;
197      _write   = 0;
198    }
199
200  template<class T>
201    Circular_Buffer<T>::Circular_Buffer(int n)
202    {
203      alloc(n);
204      _read    = 0;
205      _write   = 0;
206      _rw_dist = 0;
207    }
208
209  template<class T>
210    Circular_Buffer<T>::Circular_Buffer(const Circular_Buffer<T> &cb)
211    {
212      _data    = NULL;
213      _ndata   = 0;
214      _read    = cb._read;
215      _write   = cb._write;
216      _rw_dist = cb._rw_dist;
217
218      alloc(cb._ndata);
219      for (int i=0; i<cb._ndata; i++) { _data[i] = cb._data[i]; }
220    }
221
222  template<class T>
223    Circular_Buffer<T>::~Circular_Buffer()
224    {
225      free();
226    }
227
228  template <class T>
229    void Circular_Buffer<T>::get(T& out)
230    {
231      it_assert_debug(_rw_dist>0,"Buffer empty. No data left to read from the buffer.");
232      out=_data[_read];
233      _read++;
234      _rw_dist--;
235
236      if (_read==_ndata) { _read=0; }
237    }
238
239  template <class T>
240    T Circular_Buffer<T>::get()
241    {
242      T out;
243
244      get(out);
245      return out;
246    }
247
248  template <class T>
249    void Circular_Buffer<T>::get(Vec<T>& out, const int N)
250    {
251      int N_out;
252
253      if (N==-1)
254        N_out=_rw_dist;
255      else
256        N_out=N;
257
258      out.set_size(N_out);
259
260      for (int i=0;i<N_out;i++)
261        {
262          it_assert_debug(_rw_dist>0,"Buffer empty. No data left to read from the buffer.");
263          out(i)=_data[_read];
264          _read++;
265          _rw_dist--;
266
267          if (_read==_ndata)
268            _read=0;
269        }
270    }
271
272  template <class T>
273    void Circular_Buffer<T>::get(Array<T>& out, const int N)
274    {
275      int N_out;
276
277      if (N==-1)
278        N_out=_rw_dist;
279      else
280        N_out=N;
281
282      out.set_size(N_out);
283
284      for (int i=0;i<N_out;i++)
285        {
286          it_assert_debug(_rw_dist>0,"Buffer empty. No data left to read from the buffer.");
287          out(i)=_data[_read];
288          _read++;
289          _rw_dist--;
290
291          if (_read==_ndata)
292            _read=0;
293        }
294    }
295
296  template <class T>
297    void Circular_Buffer<T>::peek(T& out) const
298    {
299      it_assert_debug(_rw_dist>0,"Attempted to peek at an empty buffer.");
300      out=_data[_read];
301    }
302
303  template <class T>
304    T Circular_Buffer<T>::peek() const
305    {
306      T out;
307
308      peek(out);
309      return out;
310    }
311
312  template <class T>
313    void Circular_Buffer<T>::peek(const int index, T& out) const
314    {
315      it_assert_debug(_rw_dist>index && index>=0,"The index exceeds the number of elements stored in the buffer.");
316      out=_data[(_read+index)%_ndata];
317    }
318
319  template <class T>
320    void Circular_Buffer<T>::peek(Vec<T>& out, const int N) const
321    {
322      int N_out;
323      int read_tmp=_read;
324
325      if (N==-1)
326        N_out=_rw_dist;
327      else
328        N_out=N;
329
330      it_assert_debug(_rw_dist>=N_out,"Attempted to peek at more elements than there are stored in the buffer.");
331      out.set_size(N_out);
332
333      for (int i=0;i<N_out;i++)
334        {
335          out(i)=_data[read_tmp];
336          read_tmp++;
337          if (read_tmp==_ndata)
338            read_tmp=0;
339        }
340    }
341
342  template <class T>
343    void Circular_Buffer<T>::peek(const ivec& index, Vec<T>& out) const
344    {
345      out.set_size(index.size());
346
347      for (int i=0;i<index.size();i++)
348        {
349          it_assert_debug(_rw_dist>=index(i) && index(i)>=0,"Attempted to peek at an element, whose index exceeds the number of buffered elements.");
350          out(i)=_data[(_read+index(i))%_ndata];
351        }
352    }
353
354  template <class T>
355    void Circular_Buffer<T>::peek(Array<T>& out, const int N) const
356    {
357      int N_out;
358      int read_tmp=_read;
359
360      if (N==-1)
361        N_out=_rw_dist;
362      else
363        N_out=N;
364
365      it_assert_debug(_rw_dist>=N_out,"Attempted to peek at more elements than there are stored in the buffer.");
366      out.set_size(N_out);
367
368      for (int i=0;i<N_out;i++)
369        {
370          out(i)=_data[read_tmp];
371          read_tmp++;
372          if (read_tmp==_ndata)
373            read_tmp=0;
374        }
375    }
376
377  template <class T>
378    void Circular_Buffer<T>::peek(const ivec& index, Array<T>& out) const
379    {
380      out.set_size(index.size());
381
382      for (int i=0;i<index.size();i++)
383        {
384          it_assert_debug(_rw_dist>=index(i) && index(i)>=0,"Attempted to peek at an element, whose index exceeds the number of buffered elements.");
385          out(i)=_data[(_read+index(i))%_ndata];
386        }
387    }
388
389  template <class T>
390    void Circular_Buffer<T>::peek_reverse(T& out) const
391    {
392      int read_tmp;
393
394      it_assert_debug(_rw_dist>0,"Attempted to peek at an empty buffer.");
395
396      if (_write>0)
397        read_tmp=_write-1;
398      else
399        read_tmp=_ndata-1;
400
401      out=_data[read_tmp];
402    }
403
404  template <class T>
405    T Circular_Buffer<T>::peek_reverse() const
406    {
407      T out;
408
409      peek_reverse(out);
410      return out;
411    }
412
413  template <class T>
414    void Circular_Buffer<T>::peek_reverse(Vec<T>& out, const int N) const
415    {
416      int N_out;
417      int read_tmp;
418
419      if (N==-1)
420        N_out=_rw_dist;
421      else
422        N_out=N;
423
424      it_assert_debug(_rw_dist>=N_out,"Attempted to peek at more elements than there are stored in the buffer.");
425      out.set_size(N_out);
426
427      if (_write>0)
428        read_tmp=_write-1;
429      else
430        read_tmp=_ndata-1;
431
432      for (int i=0;i<N_out;i++)
433        {
434          out(i)=_data[read_tmp];
435          read_tmp--;
436          if (read_tmp<0)
437            read_tmp=_ndata-1;
438        }
439    }
440
441  template <class T>
442    void Circular_Buffer<T>::peek_reverse(Array<T>& out, const int N) const
443    {
444      int N_out;
445      int read_tmp;
446
447      if (N==-1)
448        N_out=_rw_dist;
449      else
450        N_out=N;
451
452      it_assert_debug(_rw_dist>=N_out,"Attempted to peek at more elements than there are stored in the buffer.");
453      out.set_size(N_out);
454
455      if (_write>0)
456        read_tmp=_write-1;
457      else
458        read_tmp=_ndata-1;
459
460      for (int i=0;i<N_out;i++)
461        {
462          out(i)=_data[read_tmp];
463          read_tmp--;
464          if (read_tmp<0)
465            read_tmp=_ndata-1;
466        }
467    }
468
469  template <class T>
470    void Circular_Buffer<T>::put(const T& in)
471    {
472      //Remove the oldest element of the buffer if the buffer is full
473      if (_rw_dist>=_ndata)
474        {
475          T dummy;
476          get(dummy);
477        }
478
479      //Write data to the buffer and move the pointer to the next buffer slot
480      _data[_write]=in;
481      _write++;
482      _rw_dist++;
483
484      //Check if the pointer in the circular buffer should go back to zero
485      if (_write>=_ndata)
486        _write=0;
487
488    }
489
490  template <class T>
491    void Circular_Buffer<T>::put(const Vec<T>& in)
492    {
493      for (int i=0;i<in.size();i++)
494        {
495          //Remove the oldest element of the buffer if the buffer is full
496          if (_rw_dist>=_ndata)
497            {
498              T dummy;
499              get(dummy);
500            }
501
502          //Write data to the buffer and move the pointer to the next buffer slot
503          _data[_write]=in(i);
504          _write++;
505          _rw_dist++;
506
507          //Check if the pointer in the circular buffer should go back to zero
508          if (_write>=_ndata)
509            _write=0;
510        }
511
512    }
513
514  template <class T>
515    void Circular_Buffer<T>::put(const Array<T>& in)
516    {
517      for (int i=0;i<in.size();i++)
518        {
519          //Remove the oldest element of the buffer if the buffer is full
520          if (_rw_dist>=_ndata)
521            {
522              T dummy;
523              get(dummy);
524            }
525
526          //Write data to the buffer and move the pointer to the next buffer slot
527          _data[_write]=in(i);
528          _write++;
529          _rw_dist++;
530
531          //Check if the pointer in the circular buffer should go back to zero
532          if (_write>=_ndata)
533            _write=0;
534        }
535    }
536
537  template <class T>
538    void Circular_Buffer<T>::clear()
539    {
540      _write   = 0;
541      _read    = 0;
542      _rw_dist = 0;
543    }
544
545  template<class T>
546    void Circular_Buffer<T>::alloc(int n)
547    {
548      if (n == 0) {
549        _ndata = 0;
550        _data  = NULL;
551      }
552      else if (n>0) {
553        _ndata = n;
554        _data = new T[_ndata];
555        it_assert(_data!=0, "Out of memory in Circular_Buffer::alloc");
556      }
557      else {
558        it_error("Circular_Buffer<T>::alloc(int n): n must be positive");
559      }
560    }
561
562  template<class T>
563    void Circular_Buffer<T>::free()
564    {
565      delete [] _data;
566
567      _data    = NULL;
568      _ndata   = 0;
569      _write   = 0;
570      _read    = 0;
571      _rw_dist = 0;
572    }
573
574  template<class T>
575    void Circular_Buffer<T>::operator=(const Circular_Buffer<T> &s)
576    {
577      set_size(s._ndata);
578      for (int i=0; i<_ndata; i++)
579        _data[i] = s._data[i];
580      _read=s._read;
581      _write=s._write;
582      _rw_dist=_write-_read;
583    }
584
585  template<class T>
586    void Circular_Buffer<T>::set_size(int sz, bool copy)
587    {
588      int i, min_nrof_elem;
589      //T *tmp;
590      Vec<T> tmp;
591
592      if (_ndata == sz)
593        return;
594
595      if (copy)
596        {
597          peek_reverse(tmp,-1);
598          min_nrof_elem = _rw_dist < sz ? _rw_dist : sz;
599          alloc(sz);
600          clear();
601          for (i=0; i<min_nrof_elem; i++)
602            put(tmp(min_nrof_elem-1-i));
603        }
604      else
605        {
606          free();
607          alloc(sz);
608        }
609
610      _ndata = sz;
611    }
612
613} // namespace itpp
614
615#endif // #ifndef CIRCULAR_BUFFER_H
Note: See TracBrowser for help on using the browser.