Ardour  9.0-pre0-582-g084a23a80d
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 #pragma once
24 
25 #include <atomic>
26 #include <cstring>
27 
28 #include "pbd/libpbd_visibility.h"
29 
30 namespace PBD {
31 
32 template<class T>
33 class /*LIBPBD_API*/ RingBuffer
34 {
35 public:
36  RingBuffer (size_t sz) {
37 #if 0
38  size = ffs(sz); /* find first [bit] set is a single inlined assembly instruction. But it looks like the API rounds up so... */
39 #endif
40  size_t power_of_two;
41  for (power_of_two = 1; 1U<<power_of_two < sz; power_of_two++) {}
42  size = 1<<power_of_two;
43  size_mask = size;
44  size_mask -= 1;
45  buf = new T[size];
46  reset ();
47  }
48 
49  virtual ~RingBuffer() {
50  delete [] buf;
51  }
52 
53  void reset () {
54  /* !!! NOT THREAD SAFE !!! */
55  write_idx.store (0);
56  read_idx.store (0);
57  }
58 
59  void set (size_t r, size_t w) {
60  /* !!! NOT THREAD SAFE !!! */
61  write_idx.store (w);
62  read_idx.store (r);
63  }
64 
65  size_t read (T *dest, size_t cnt);
66  size_t write (T const * src, size_t cnt);
67 
68  struct rw_vector {
69  T *buf[2];
70  size_t len[2];
71  };
72 
73  void get_read_vector (rw_vector *);
74  void get_write_vector (rw_vector *);
75 
76  void decrement_read_idx (size_t cnt) {
77  read_idx.store ((read_idx.load() - cnt) & size_mask);
78  }
79 
80  void increment_read_idx (size_t cnt) {
81  read_idx.store ((read_idx.load () + cnt) & size_mask);
82  }
83 
84  void increment_write_idx (size_t cnt) {
85  write_idx.store ((write_idx.load () + cnt) & size_mask);
86  }
87 
88  size_t write_space () const {
89  size_t w, r;
90 
91  w = write_idx.load ();
92  r = read_idx.load ();
93 
94  if (w > r) {
95  return ((r - w + size) & size_mask) - 1;
96  } else if (w < r) {
97  return (r - w) - 1;
98  } else {
99  return size - 1;
100  }
101  }
102 
103  size_t read_space () const {
104  size_t w, r;
105 
106  w = write_idx.load ();
107  r = read_idx.load ();
108 
109  if (w > r) {
110  return w - r;
111  } else {
112  return (w - r + size) & size_mask;
113  }
114  }
115 
116  T *buffer () { return buf; }
117  size_t get_write_idx () const { return write_idx.load (); }
118  size_t get_read_idx () const { return read_idx.load (); }
119  size_t bufsize () const { return size; }
120 
121 protected:
122  T *buf;
123  size_t size;
124  size_t size_mask;
125  mutable std::atomic<int> write_idx;
126  mutable std::atomic<int> read_idx;
127 
128 private:
130 };
131 
132 template<class T> /*LIBPBD_API*/ size_t
133 RingBuffer<T>::read (T *dest, size_t cnt)
134 {
135  size_t free_cnt;
136  size_t cnt2;
137  size_t to_read;
138  size_t n1, n2;
139  size_t priv_read_idx;
140 
141  priv_read_idx = read_idx.load ();
142 
143  if ((free_cnt = read_space ()) == 0) {
144  return 0;
145  }
146 
147  to_read = cnt > free_cnt ? free_cnt : cnt;
148 
149  cnt2 = priv_read_idx + to_read;
150 
151  if (cnt2 > size) {
152  n1 = size - priv_read_idx;
153  n2 = cnt2 & size_mask;
154  } else {
155  n1 = to_read;
156  n2 = 0;
157  }
158 
159  memcpy (dest, &buf[priv_read_idx], n1 * sizeof (T));
160  priv_read_idx = (priv_read_idx + n1) & size_mask;
161 
162  if (n2) {
163  memcpy (dest+n1, buf, n2 * sizeof (T));
164  priv_read_idx = n2;
165  }
166 
167  read_idx.store (priv_read_idx);
168  return to_read;
169 }
170 
171 template<class T> /*LIBPBD_API*/ size_t
172 RingBuffer<T>::write (T const *src, size_t cnt)
173 
174 {
175  size_t free_cnt;
176  size_t cnt2;
177  size_t to_write;
178  size_t n1, n2;
179  size_t priv_write_idx;
180 
181  priv_write_idx = write_idx.load ();
182 
183  if ((free_cnt = write_space ()) == 0) {
184  return 0;
185  }
186 
187  to_write = cnt > free_cnt ? free_cnt : cnt;
188 
189  cnt2 = priv_write_idx + to_write;
190 
191  if (cnt2 > size) {
192  n1 = size - priv_write_idx;
193  n2 = cnt2 & size_mask;
194  } else {
195  n1 = to_write;
196  n2 = 0;
197  }
198 
199  memcpy (&buf[priv_write_idx], src, n1 * sizeof (T));
200  priv_write_idx = (priv_write_idx + n1) & size_mask;
201 
202  if (n2) {
203  memcpy (buf, src+n1, n2 * sizeof (T));
204  priv_write_idx = n2;
205  }
206 
207  write_idx.store (priv_write_idx);
208  return to_write;
209 }
210 
211 template<class T> /*LIBPBD_API*/ void
213 
214 {
215  size_t free_cnt;
216  size_t cnt2;
217  size_t w, r;
218 
219  w = write_idx.load ();
220  r = read_idx.load ();
221 
222  if (w > r) {
223  free_cnt = w - r;
224  } else {
225  free_cnt = (w - r + size) & size_mask;
226  }
227 
228  cnt2 = r + free_cnt;
229 
230  if (cnt2 > size) {
231  /* Two part vector: the rest of the buffer after the
232  current write ptr, plus some from the start of
233  the buffer.
234  */
235 
236  vec->buf[0] = &buf[r];
237  vec->len[0] = size - r;
238  vec->buf[1] = buf;
239  vec->len[1] = cnt2 & size_mask;
240 
241  } else {
242 
243  /* Single part vector: just the rest of the buffer */
244 
245  vec->buf[0] = &buf[r];
246  vec->len[0] = free_cnt;
247  vec->buf[1] = 0;
248  vec->len[1] = 0;
249  }
250 }
251 
252 template<class T> /*LIBPBD_API*/ void
254 
255 {
256  size_t free_cnt;
257  size_t cnt2;
258  size_t w, r;
259 
260  w = write_idx.load ();
261  r = read_idx.load ();
262 
263  if (w > r) {
264  free_cnt = ((r - w + size) & size_mask) - 1;
265  } else if (w < r) {
266  free_cnt = (r - w) - 1;
267  } else {
268  free_cnt = size - 1;
269  }
270 
271  cnt2 = w + free_cnt;
272 
273  if (cnt2 > size) {
274 
275  /* Two part vector: the rest of the buffer after the
276  current write ptr, plus some from the start of
277  the buffer.
278  */
279 
280  vec->buf[0] = &buf[w];
281  vec->len[0] = size - w;
282  vec->buf[1] = buf;
283  vec->len[1] = cnt2 & size_mask;
284  } else {
285  vec->buf[0] = &buf[w];
286  vec->len[0] = free_cnt;
287  vec->len[1] = 0;
288  }
289 }
290 
291 } /* end namespace */
292 
void increment_read_idx(size_t cnt)
Definition: ringbuffer.h:80
size_t size_mask
Definition: ringbuffer.h:124
void get_write_vector(rw_vector *)
Definition: ringbuffer.h:253
RingBuffer(RingBuffer const &)
std::atomic< int > write_idx
Definition: ringbuffer.h:125
void decrement_read_idx(size_t cnt)
Definition: ringbuffer.h:76
virtual ~RingBuffer()
Definition: ringbuffer.h:49
void increment_write_idx(size_t cnt)
Definition: ringbuffer.h:84
size_t read(T *dest, size_t cnt)
Definition: ringbuffer.h:133
void set(size_t r, size_t w)
Definition: ringbuffer.h:59
size_t write_space() const
Definition: ringbuffer.h:88
std::atomic< int > read_idx
Definition: ringbuffer.h:126
RingBuffer(size_t sz)
Definition: ringbuffer.h:36
size_t get_write_idx() const
Definition: ringbuffer.h:117
size_t write(T const *src, size_t cnt)
Definition: ringbuffer.h:172
size_t get_read_idx() const
Definition: ringbuffer.h:118
size_t bufsize() const
Definition: ringbuffer.h:119
size_t read_space() const
Definition: ringbuffer.h:103
void get_read_vector(rw_vector *)
Definition: ringbuffer.h:212
Definition: axis_view.h:42
int ffs(int x)