RAUL
0.7.0
|
00001 /* This file is part of Raul. 00002 * Copyright (C) 2007-2009 David 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 <cstring> 00023 #include <cstdlib> 00024 #include <iostream> 00025 #include <glib.h> 00026 #include "raul/log.hpp" 00027 00028 namespace Raul { 00029 00030 00035 template <typename T> 00036 class RingBuffer { 00037 public: 00040 RingBuffer(size_t size) 00041 : _size(size) 00042 , _buf(static_cast<char*>(malloc(size))) 00043 { 00044 reset(); 00045 assert(read_space() == 0); 00046 assert(write_space() == size - 1); 00047 } 00048 00049 virtual ~RingBuffer() { 00050 free(_buf); 00051 } 00052 00056 void reset() { 00057 g_atomic_int_set(&_write_ptr, 0); 00058 g_atomic_int_set(&_read_ptr, 0); 00059 } 00060 00061 size_t write_space() const { 00062 const size_t w = g_atomic_int_get(&_write_ptr); 00063 const size_t r = g_atomic_int_get(&_read_ptr); 00064 00065 if (w > r) { 00066 return ((r - w + _size) % _size) - 1; 00067 } else if (w < r) { 00068 return (r - w) - 1; 00069 } else { 00070 return _size - 1; 00071 } 00072 } 00073 00074 size_t read_space() const { 00075 const size_t w = g_atomic_int_get(&_write_ptr); 00076 const size_t r = g_atomic_int_get(&_read_ptr); 00077 00078 if (w > r) { 00079 return w - r; 00080 } else { 00081 return (w - r + _size) % _size; 00082 } 00083 } 00084 00085 size_t capacity() const { return _size; } 00086 00087 size_t peek(size_t size, T* dst); 00088 bool full_peek(size_t size, T* dst); 00089 00090 size_t read(size_t size, T* dst); 00091 bool full_read(size_t size, T* dst); 00092 00093 bool skip(size_t size); 00094 00095 void write(size_t size, const T* src); 00096 00097 protected: 00098 mutable int _write_ptr; 00099 mutable int _read_ptr; 00100 00101 size_t _size; 00102 char* _buf; 00103 }; 00104 00105 00112 template<typename T> 00113 size_t 00114 RingBuffer<T>::peek(size_t size, T* dst) 00115 { 00116 const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr); 00117 00118 const size_t read_size = (priv_read_ptr + size < _size) 00119 ? size 00120 : _size - priv_read_ptr; 00121 00122 memcpy(dst, &_buf[priv_read_ptr], read_size); 00123 00124 return read_size; 00125 } 00126 00127 00128 template<typename T> 00129 bool 00130 RingBuffer<T>::full_peek(size_t size, T* dst) 00131 { 00132 if (read_space() < size) { 00133 return false; 00134 } 00135 00136 const size_t read_size = peek(size, dst); 00137 00138 if (read_size < size) { 00139 peek(size - read_size, dst + read_size); 00140 } 00141 00142 return true; 00143 } 00144 00145 00152 template<typename T> 00153 size_t 00154 RingBuffer<T>::read(size_t size, T* dst) 00155 { 00156 const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr); 00157 00158 const size_t read_size = (priv_read_ptr + size < _size) 00159 ? size 00160 : _size - priv_read_ptr; 00161 00162 memcpy(dst, &_buf[priv_read_ptr], read_size); 00163 00164 g_atomic_int_set(&_read_ptr, (priv_read_ptr + read_size) % _size); 00165 00166 return read_size; 00167 } 00168 00169 00170 template<typename T> 00171 bool 00172 RingBuffer<T>::full_read(size_t size, T* dst) 00173 { 00174 if (read_space() < size) { 00175 return false; 00176 } 00177 00178 const size_t read_size = read(size, dst); 00179 00180 if (read_size < size) { 00181 read(size - read_size, dst + read_size); 00182 } 00183 00184 return true; 00185 } 00186 00187 00188 template<typename T> 00189 bool 00190 RingBuffer<T>::skip(size_t size) 00191 { 00192 if (read_space() < size) { 00193 warn << "Attempt to skip past end of RingBuffer" << std::endl; 00194 return false; 00195 } 00196 00197 const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr); 00198 g_atomic_int_set(&_read_ptr, (priv_read_ptr + size) % _size); 00199 00200 return true; 00201 } 00202 00203 00204 template<typename T> 00205 inline void 00206 RingBuffer<T>::write(size_t size, const T* src) 00207 { 00208 const size_t priv_write_ptr = g_atomic_int_get(&_write_ptr); 00209 00210 if (priv_write_ptr + size <= _size) { 00211 memcpy(&_buf[priv_write_ptr], src, size); 00212 g_atomic_int_set(&_write_ptr, (priv_write_ptr + size) % _size); 00213 } else { 00214 const size_t this_size = _size - priv_write_ptr; 00215 assert(this_size < size); 00216 assert(priv_write_ptr + this_size <= _size); 00217 memcpy(&_buf[priv_write_ptr], src, this_size); 00218 memcpy(&_buf[0], src+this_size, size - this_size); 00219 g_atomic_int_set(&_write_ptr, size - this_size); 00220 } 00221 } 00222 00223 00224 } // namespace Raul 00225 00226 #endif // RAUL_RING_BUFFER_HPP 00227