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
Generated on Fri May 1 11:09:15 2009 for IT++ by Doxygen 1.5.8