Ardour  8.12
ringbuffer.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2000-2015 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2006-2007 Taybin Rutkin <taybin@taybin.com>
4  * Copyright (C) 2008-2009 David Robillard <d@drobilla.net>
5  * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
6  * Copyright (C) 2013 John Emmas <john@creativepost.co.uk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 #ifndef ringbuffer_h
24 #define ringbuffer_h
25 
26 #include <atomic>
27 #include <cstring>
28 
29 #include "pbd/libpbd_visibility.h"
30 
31 namespace PBD {
32 
33 template<class T>
34 class /*LIBPBD_API*/ RingBuffer
35 {
36 public:
37  RingBuffer (size_t sz) {
38 #if 0
39  size = ffs(sz); /* find first [bit] set is a single inlined assembly instruction. But it looks like the API rounds up so... */
40 #endif
41  size_t power_of_two;
42  for (power_of_two = 1; 1U<<power_of_two < sz; power_of_two++) {}
43  size = 1<<power_of_two;
44  size_mask = size;
45  size_mask -= 1;
46  buf = new T[size];
47  reset ();
48  }
49 
50  virtual ~RingBuffer() {
51  delete [] buf;
52  }
53 
54  void reset () {
55  /* !!! NOT THREAD SAFE !!! */
56  write_idx.store (0);
57  read_idx.store (0);
58  }
59 
60  void set (size_t r, size_t w) {
61  /* !!! NOT THREAD SAFE !!! */
62  write_idx.store (w);
63  read_idx.store (r);
64  }
65 
66  size_t read (T *dest, size_t cnt);
67  size_t write (T const * src, size_t cnt);
68 
69  struct rw_vector {
70  T *buf[2];
71  size_t len[2];
72  };
73 
74  void get_read_vector (rw_vector *);
75  void get_write_vector (rw_vector *);
76 
77  void decrement_read_idx (size_t cnt) {
78  read_idx.store ((read_idx.load() - cnt) & size_mask);
79  }
80 
81  void increment_read_idx (size_t cnt) {
82  read_idx.store ((read_idx.load () + cnt) & size_mask);
83  }
84 
85  void increment_write_idx (size_t cnt) {
86  write_idx.store ((write_idx.load () + cnt) & size_mask);
87  }
88 
89  size_t write_space () const {
90  size_t w, r;
91 
92  w = write_idx.load ();
93  r = read_idx.load ();
94 
95  if (w > r) {
96  return ((r - w + size) & size_mask) - 1;
97  } else if (w < r) {
98  return (r - w) - 1;
99  } else {
100  return size - 1;
101  }
102  }
103 
104  size_t read_space () const {
105  size_t w, r;
106 
107  w = write_idx.load ();
108  r = read_idx.load ();
109 
110  if (w > r) {
111  return w - r;
112  } else {
113  return (w - r + size) & size_mask;
114  }
115  }
116 
117  T *buffer () { return buf; }
118  size_t get_write_idx () const { return write_idx.load (); }
119  size_t get_read_idx () const { return read_idx.load (); }
120  size_t bufsize () const { return size; }
121 
122 protected:
123  T *buf;
124  size_t size;
125  size_t size_mask;
126  mutable std::atomic<int> write_idx;
127  mutable std::atomic<int> read_idx;
128 
129 private:
131 };
132 
133 template<class T> /*LIBPBD_API*/ size_t
134 RingBuffer<T>::read (T *dest, size_t cnt)
135 {
136  size_t free_cnt;
137  size_t cnt2;
138  size_t to_read;
139  size_t n1, n2;
140  size_t priv_read_idx;
141 
142  priv_read_idx = read_idx.load ();
143 
144  if ((free_cnt = read_space ()) == 0) {
145  return 0;
146  }
147 
148  to_read = cnt > free_cnt ? free_cnt : cnt;
149 
150  cnt2 = priv_read_idx + to_read;
151 
152  if (cnt2 > size) {
153  n1 = size - priv_read_idx;
154  n2 = cnt2 & size_mask;
155  } else {
156  n1 = to_read;
157  n2 = 0;
158  }
159 
160  memcpy (dest, &buf[priv_read_idx], n1 * sizeof (T));
161  priv_read_idx = (priv_read_idx + n1) & size_mask;
162 
163  if (n2) {
164  memcpy (dest+n1, buf, n2 * sizeof (T));
165  priv_read_idx = n2;
166  }
167 
168  read_idx.store (priv_read_idx);
169  return to_read;
170 }
171 
172 template<class T> /*LIBPBD_API*/ size_t
173 RingBuffer<T>::write (T const *src, size_t cnt)
174 
175 {
176  size_t free_cnt;
177  size_t cnt2;
178  size_t to_write;
179  size_t n1, n2;
180  size_t priv_write_idx;
181 
182  priv_write_idx = write_idx.load ();
183 
184  if ((free_cnt = write_space ()) == 0) {
185  return 0;
186  }
187 
188  to_write = cnt > free_cnt ? free_cnt : cnt;
189 
190  cnt2 = priv_write_idx + to_write;
191 
192  if (cnt2 > size) {
193  n1 = size - priv_write_idx;
194  n2 = cnt2 & size_mask;
195  } else {
196  n1 = to_write;
197  n2 = 0;
198  }
199 
200  memcpy (&buf[priv_write_idx], src, n1 * sizeof (T));
201  priv_write_idx = (priv_write_idx + n1) & size_mask;
202 
203  if (n2) {
204  memcpy (buf, src+n1, n2 * sizeof (T));
205  priv_write_idx = n2;
206  }
207 
208  write_idx.store (priv_write_idx);
209  return to_write;
210 }
211 
212 template<class T> /*LIBPBD_API*/ void
214 
215 {
216  size_t free_cnt;
217  size_t cnt2;
218  size_t w, r;
219 
220  w = write_idx.load ();
221  r = read_idx.load ();
222 
223  if (w > r) {
224  free_cnt = w - r;
225  } else {
226  free_cnt = (w - r + size) & size_mask;
227  }
228 
229  cnt2 = r + free_cnt;
230 
231  if (cnt2 > size) {
232  /* Two part vector: the rest of the buffer after the
233  current write ptr, plus some from the start of
234  the buffer.
235  */
236 
237  vec->buf[0] = &buf[r];
238  vec->len[0] = size - r;
239  vec->buf[1] = buf;
240  vec->len[1] = cnt2 & size_mask;
241 
242  } else {
243 
244  /* Single part vector: just the rest of the buffer */
245 
246  vec->buf[0] = &buf[r];
247  vec->len[0] = free_cnt;
248  vec->buf[1] = 0;
249  vec->len[1] = 0;
250  }
251 }
252 
253 template<class T> /*LIBPBD_API*/ void
255 
256 {
257  size_t free_cnt;
258  size_t cnt2;
259  size_t w, r;
260 
261  w = write_idx.load ();
262  r = read_idx.load ();
263 
264  if (w > r) {
265  free_cnt = ((r - w + size) & size_mask) - 1;
266  } else if (w < r) {
267  free_cnt = (r - w) - 1;
268  } else {
269  free_cnt = size - 1;
270  }
271 
272  cnt2 = w + free_cnt;
273 
274  if (cnt2 > size) {
275 
276  /* Two part vector: the rest of the buffer after the
277  current write ptr, plus some from the start of
278  the buffer.
279  */
280 
281  vec->buf[0] = &buf[w];
282  vec->len[0] = size - w;
283  vec->buf[1] = buf;
284  vec->len[1] = cnt2 & size_mask;
285  } else {
286  vec->buf[0] = &buf[w];
287  vec->len[0] = free_cnt;
288  vec->len[1] = 0;
289  }
290 }
291 
292 } /* end namespace */
293 
294 #endif /* __ringbuffer_h__ */
void increment_read_idx(size_t cnt)
Definition: ringbuffer.h:81
size_t size_mask
Definition: ringbuffer.h:125
void get_write_vector(rw_vector *)
Definition: ringbuffer.h:254
RingBuffer(RingBuffer const &)
std::atomic< int > write_idx
Definition: ringbuffer.h:126
void decrement_read_idx(size_t cnt)
Definition: ringbuffer.h:77
virtual ~RingBuffer()
Definition: ringbuffer.h:50
void increment_write_idx(size_t cnt)
Definition: ringbuffer.h:85
size_t read(T *dest, size_t cnt)
Definition: ringbuffer.h:134
void set(size_t r, size_t w)
Definition: ringbuffer.h:60
size_t write_space() const
Definition: ringbuffer.h:89
std::atomic< int > read_idx
Definition: ringbuffer.h:127
RingBuffer(size_t sz)
Definition: ringbuffer.h:37
size_t get_write_idx() const
Definition: ringbuffer.h:118
size_t write(T const *src, size_t cnt)
Definition: ringbuffer.h:173
size_t get_read_idx() const
Definition: ringbuffer.h:119
size_t bufsize() const
Definition: ringbuffer.h:120
size_t read_space() const
Definition: ringbuffer.h:104
void get_read_vector(rw_vector *)
Definition: ringbuffer.h:213
Definition: axis_view.h:42
int ffs(int x)