RAUL  0.5.1
RingBuffer.hpp
1 /* This file is part of Raul.
2  * Copyright (C) 2007-2008 Dave Robillard <http://drobilla.net>
3  *
4  * Raul is free software; you can redistribute it and/or modify it under the
5  * terms of the GNU General Public License as published by the Free Software
6  * Foundation; either version 2 of the License, or (at your option) any later
7  * version.
8  *
9  * Raul is distributed in the hope that it will be useful, but WITHOUT ANY
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16  */
17 
18 #ifndef RAUL_RING_BUFFER_HPP
19 #define RAUL_RING_BUFFER_HPP
20 
21 #include <cassert>
22 #include <iostream>
23 #include <glib.h>
24 
25 namespace Raul {
26 
27 
32 template <typename T>
33 class RingBuffer {
34 public:
35 
38  RingBuffer(size_t size)
39  : _size(size)
40  , _buf(new T[size])
41  {
42  reset();
43  assert(read_space() == 0);
44  assert(write_space() == size - 1);
45  }
46 
47  virtual ~RingBuffer() {
48  delete[] _buf;
49  }
50 
54  void reset() {
55  g_atomic_int_set(&_write_ptr, 0);
56  g_atomic_int_set(&_read_ptr, 0);
57  }
58 
59  size_t write_space() const {
60 
61  const size_t w = g_atomic_int_get(&_write_ptr);
62  const size_t r = g_atomic_int_get(&_read_ptr);
63 
64  if (w > r) {
65  return ((r - w + _size) % _size) - 1;
66  } else if (w < r) {
67  return (r - w) - 1;
68  } else {
69  return _size - 1;
70  }
71  }
72 
73  size_t read_space() const {
74 
75  const size_t w = g_atomic_int_get(&_write_ptr);
76  const size_t r = g_atomic_int_get(&_read_ptr);
77 
78  if (w > r) {
79  return w - r;
80  } else {
81  return (w - r + _size) % _size;
82  }
83  }
84 
85  size_t capacity() const { return _size; }
86 
87  size_t peek(size_t size, T* dst);
88  bool full_peek(size_t size, T* dst);
89 
90  size_t read(size_t size, T* dst);
91  bool full_read(size_t size, T* dst);
92 
93  bool skip(size_t size);
94 
95  void write(size_t size, const T* src);
96 
97 protected:
98  mutable int _write_ptr;
99  mutable int _read_ptr;
100 
101  size_t _size;
102  T* _buf;
103 };
104 
105 
112 template<typename T>
113 size_t
114 RingBuffer<T>::peek(size_t size, T* dst)
115 {
116  const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
117 
118  const size_t read_size = (priv_read_ptr + size < _size)
119  ? size
120  : _size - priv_read_ptr;
121 
122  memcpy(dst, &_buf[priv_read_ptr], read_size);
123 
124  return read_size;
125 }
126 
127 
128 template<typename T>
129 bool
130 RingBuffer<T>::full_peek(size_t size, T* dst)
131 {
132  if (read_space() < size) {
133  return false;
134  }
135 
136  const size_t read_size = peek(size, dst);
137 
138  if (read_size < size) {
139  peek(size - read_size, dst + read_size);
140  }
141 
142  return true;
143 }
144 
145 
152 template<typename T>
153 size_t
154 RingBuffer<T>::read(size_t size, T* dst)
155 {
156  const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
157 
158  const size_t read_size = (priv_read_ptr + size < _size)
159  ? size
160  : _size - priv_read_ptr;
161 
162  memcpy(dst, &_buf[priv_read_ptr], read_size);
163 
164  g_atomic_int_set(&_read_ptr, (priv_read_ptr + read_size) % _size);
165 
166  return read_size;
167 }
168 
169 
170 template<typename T>
171 bool
172 RingBuffer<T>::full_read(size_t size, T* dst)
173 {
174  if (read_space() < size) {
175  return false;
176  }
177 
178  const size_t read_size = read(size, dst);
179 
180  if (read_size < size) {
181  read(size - read_size, dst + read_size);
182  }
183 
184  return true;
185 }
186 
187 
188 template<typename T>
189 bool
190 RingBuffer<T>::skip(size_t size)
191 {
192  if (read_space() < size) {
193  std::cerr << "WARNING: Attempt to skip past end of MIDI ring buffer" << std::endl;
194  return false;
195  }
196 
197  const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
198  g_atomic_int_set(&_read_ptr, (priv_read_ptr + size) % _size);
199 
200  return true;
201 }
202 
203 
204 template<typename T>
205 inline void
206 RingBuffer<T>::write(size_t size, const T* src)
207 {
208  const size_t priv_write_ptr = g_atomic_int_get(&_write_ptr);
209 
210  if (priv_write_ptr + size <= _size) {
211  memcpy(&_buf[priv_write_ptr], src, size);
212  g_atomic_int_set(&_write_ptr, (priv_write_ptr + size) % _size);
213  } else {
214  const size_t this_size = _size - priv_write_ptr;
215  assert(this_size < size);
216  assert(priv_write_ptr + this_size <= _size);
217  memcpy(&_buf[priv_write_ptr], src, this_size);
218  memcpy(&_buf[0], src+this_size, size - this_size);
219  g_atomic_int_set(&_write_ptr, size - this_size);
220  }
221 }
222 
223 
224 } // namespace Raul
225 
226 #endif // RAUL_RING_BUFFER_HPP
227 
RingBuffer(size_t size)
Definition: RingBuffer.hpp:38
size_t _size
Size (capacity) in bytes.
Definition: RingBuffer.hpp:101
A lock-free RingBuffer.
Definition: RingBuffer.hpp:33
size_t peek(size_t size, T *dst)
Peek at the ringbuffer (read w/o advancing read pointer).
Definition: RingBuffer.hpp:114
void reset()
Reset(empty) the ringbuffer.
Definition: RingBuffer.hpp:54
Definition: Array.hpp:26
T * _buf
size, event, size, event...
Definition: RingBuffer.hpp:102
size_t read(size_t size, T *dst)
Read from the ringbuffer.
Definition: RingBuffer.hpp:154