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