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