/builddir/build/BUILD/raul-0.4.0/raul/RingBuffer.hpp

00001 /* This file is part of Raul.
00002  * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
00003  * 
00004  * Raul is free software; you can redistribute it and/or modify it under the
00005  * terms of the GNU General Public License as published by the Free Software
00006  * Foundation; either version 2 of the License, or (at your option) any later
00007  * version.
00008  * 
00009  * Raul is distributed in the hope that it will be useful, but WITHOUT ANY
00010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for details.
00012  * 
00013  * You should have received a copy of the GNU General Public License along
00014  * with this program; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00016  */
00017 
00018 #ifndef RAUL_RING_BUFFER_HPP
00019 #define RAUL_RING_BUFFER_HPP
00020 
00021 #include <cassert>
00022 #include <glib.h>
00023 
00024 namespace Raul {
00025 
00026 
00031 template <typename T>
00032 class RingBuffer {
00033 public:
00034 
00037     RingBuffer(size_t size)
00038         : _size(size)
00039         , _buf(new T[size])
00040     {
00041         reset();
00042         assert(read_space() == 0);
00043         assert(write_space() == size - 1);
00044     }
00045     
00046     virtual ~RingBuffer() {
00047         delete[] _buf;
00048     }
00049 
00053     void reset() {
00054         g_atomic_int_set(&_write_ptr, 0);
00055         g_atomic_int_set(&_read_ptr, 0);
00056     }
00057 
00058     size_t write_space() const {
00059         
00060         const size_t w = g_atomic_int_get(&_write_ptr);
00061         const size_t r = g_atomic_int_get(&_read_ptr);
00062         
00063         if (w > r) {
00064             return ((r - w + _size) % _size) - 1;
00065         } else if(w < r) {
00066             return (r - w) - 1;
00067         } else {
00068             return _size - 1;
00069         }
00070     }
00071     
00072     size_t read_space() const {
00073         
00074         const size_t w = g_atomic_int_get(&_write_ptr);
00075         const size_t r = g_atomic_int_get(&_read_ptr);
00076         
00077         if (w > r) {
00078             return w - r;
00079         } else {
00080             return (w - r + _size) % _size;
00081         }
00082     }
00083 
00084     size_t capacity() const { return _size; }
00085 
00086     size_t read(size_t size, T* dst);
00087     void   write(size_t size, const T* src);
00088     
00089     bool   full_read(size_t size, T* dst);
00090 
00091 protected:
00092     mutable gint _write_ptr;
00093     mutable gint _read_ptr;
00094     
00095     size_t _size; 
00096     T*  _buf;     
00097 };
00098 
00099 
00106 template<typename T>
00107 size_t
00108 RingBuffer<T>::read(size_t size, T* dst)
00109 {
00110     const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
00111 
00112     const size_t read_size = (priv_read_ptr + size < _size)
00113             ? size
00114             : _size - priv_read_ptr;
00115     
00116     memcpy(dst, &_buf[priv_read_ptr], read_size);
00117         
00118     g_atomic_int_set(&_read_ptr, (priv_read_ptr + read_size) % _size);
00119 
00120     return read_size;
00121 }
00122 
00123 
00124 template<typename T>
00125 inline void
00126 RingBuffer<T>::write(size_t size, const T* src)
00127 {
00128     const size_t priv_write_ptr = g_atomic_int_get(&_write_ptr);
00129     
00130     if (priv_write_ptr + size <= _size) {
00131         memcpy(&_buf[priv_write_ptr], src, size);
00132         g_atomic_int_set(&_write_ptr, (priv_write_ptr + size) % _size);
00133     } else {
00134         const size_t this_size = _size - priv_write_ptr;
00135         assert(this_size < size);
00136         assert(priv_write_ptr + this_size <= _size);
00137         memcpy(&_buf[priv_write_ptr], src, this_size);
00138         memcpy(&_buf[0], src+this_size, size - this_size);
00139         g_atomic_int_set(&_write_ptr, size - this_size);
00140     }
00141 }
00142 
00143 
00144 template<typename T>
00145 bool
00146 RingBuffer<T>::full_read(size_t size, T* dst)
00147 {
00148     if (read_space() < size)
00149         return false;
00150 
00151     const size_t read_size = read(size, dst);
00152     
00153     if (read_size < size)
00154         read(size - read_size, dst + read_size);
00155 
00156     return true;
00157 }
00158 
00159     
00160 } // namespace Raul
00161 
00162 #endif // RAUL_RING_BUFFER_HPP
00163 

Generated on Wed Apr 9 08:14:41 2008 for RAUL by  doxygen 1.5.1