Fixed i18n system.
[ardour.git] / libs / pbd / pbd / ringbuffer.h
1 /*
2     Copyright (C) 2000 Paul Davis & Benno Senoner
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #ifndef ringbuffer_h
22 #define ringbuffer_h
23
24 //#include <sys/mman.h>
25
26 #include <glib.h>
27
28 template<class T>
29 class RingBuffer 
30 {
31   public:
32         RingBuffer (size_t sz) {
33                 size_t power_of_two;
34                 
35                 for (power_of_two = 1; 1U<<power_of_two < sz; power_of_two++);
36                 
37                 size = 1<<power_of_two;
38                 size_mask = size;
39                 size_mask -= 1;
40                 buf = new T[size];
41                 reset ();
42
43         };
44         
45         virtual ~RingBuffer() {
46                 delete [] buf;
47         }
48
49         void reset () {
50                 /* !!! NOT THREAD SAFE !!! */
51                 g_atomic_int_set (&write_ptr, 0);
52                 g_atomic_int_set (&read_ptr, 0);
53         }
54
55         void set (size_t r, size_t w) {
56                 /* !!! NOT THREAD SAFE !!! */
57                 g_atomic_int_set (&write_ptr, w);
58                 g_atomic_int_set (&read_ptr, r);
59         }
60         
61         size_t  read  (T *dest, size_t cnt);
62         size_t  write (T *src, size_t cnt);
63
64         struct rw_vector {
65             T *buf[2];
66             size_t len[2];
67         };
68
69         void get_read_vector (rw_vector *);
70         void get_write_vector (rw_vector *);
71         
72         void decrement_read_ptr (size_t cnt) {
73                 g_atomic_int_set (&read_ptr, (g_atomic_int_get(&read_ptr) - cnt) & size_mask);
74         }                
75
76         void increment_read_ptr (size_t cnt) {
77                 g_atomic_int_set (&read_ptr, (g_atomic_int_get(&read_ptr) + cnt) & size_mask);
78         }                
79
80         void increment_write_ptr (size_t cnt) {
81                 g_atomic_int_set (&write_ptr,  (g_atomic_int_get(&write_ptr) + cnt) & size_mask);
82         }                
83
84         size_t write_space () {
85                 size_t w, r;
86                 
87                 w = g_atomic_int_get (&write_ptr);
88                 r = g_atomic_int_get (&read_ptr);
89                 
90                 if (w > r) {
91                         return ((r - w + size) & size_mask) - 1;
92                 } else if (w < r) {
93                         return (r - w) - 1;
94                 } else {
95                         return size - 1;
96                 }
97         }
98         
99         size_t read_space () {
100                 size_t w, r;
101                 
102                 w = g_atomic_int_get (&write_ptr);
103                 r = g_atomic_int_get (&read_ptr);
104                 
105                 if (w > r) {
106                         return w - r;
107                 } else {
108                         return (w - r + size) & size_mask;
109                 }
110         }
111
112         T *buffer () { return buf; }
113         size_t get_write_ptr () const { return g_atomic_int_get (&write_ptr); }
114         size_t get_read_ptr () const { return g_atomic_int_get (&read_ptr); }
115         size_t bufsize () const { return size; }
116
117   protected:
118         T *buf;
119         size_t size;
120         mutable gint write_ptr;
121         mutable gint read_ptr;
122         size_t size_mask;
123 };
124
125 template<class T> size_t
126 RingBuffer<T>::read (T *dest, size_t cnt)
127 {
128         size_t free_cnt;
129         size_t cnt2;
130         size_t to_read;
131         size_t n1, n2;
132         size_t priv_read_ptr;
133
134         priv_read_ptr=g_atomic_int_get(&read_ptr);
135
136         if ((free_cnt = read_space ()) == 0) {
137                 return 0;
138         }
139
140         to_read = cnt > free_cnt ? free_cnt : cnt;
141         
142         cnt2 = priv_read_ptr + to_read;
143
144         if (cnt2 > size) {
145                 n1 = size - priv_read_ptr;
146                 n2 = cnt2 & size_mask;
147         } else {
148                 n1 = to_read;
149                 n2 = 0;
150         }
151         
152         memcpy (dest, &buf[priv_read_ptr], n1 * sizeof (T));
153         priv_read_ptr = (priv_read_ptr + n1) & size_mask;
154
155         if (n2) {
156                 memcpy (dest+n1, buf, n2 * sizeof (T));
157                 priv_read_ptr = n2;
158         }
159
160         g_atomic_int_set(&read_ptr, priv_read_ptr);
161         return to_read;
162 }
163
164 template<class T> size_t
165 RingBuffer<T>::write (T *src, size_t cnt)
166
167 {
168         size_t free_cnt;
169         size_t cnt2;
170         size_t to_write;
171         size_t n1, n2;
172         size_t priv_write_ptr;
173
174         priv_write_ptr=g_atomic_int_get(&write_ptr);
175
176         if ((free_cnt = write_space ()) == 0) {
177                 return 0;
178         }
179
180         to_write = cnt > free_cnt ? free_cnt : cnt;
181         
182         cnt2 = priv_write_ptr + to_write;
183
184         if (cnt2 > size) {
185                 n1 = size - priv_write_ptr;
186                 n2 = cnt2 & size_mask;
187         } else {
188                 n1 = to_write;
189                 n2 = 0;
190         }
191
192         memcpy (&buf[priv_write_ptr], src, n1 * sizeof (T));
193         priv_write_ptr = (priv_write_ptr + n1) & size_mask;
194
195         if (n2) {
196                 memcpy (buf, src+n1, n2 * sizeof (T));
197                 priv_write_ptr = n2;
198         }
199
200         g_atomic_int_set(&write_ptr, priv_write_ptr);
201         return to_write;
202 }
203
204 template<class T> void
205 RingBuffer<T>::get_read_vector (RingBuffer<T>::rw_vector *vec)
206
207 {
208         size_t free_cnt;
209         size_t cnt2;
210         size_t w, r;
211         
212         w = g_atomic_int_get (&write_ptr);
213         r = g_atomic_int_get (&read_ptr);
214         
215         if (w > r) {
216                 free_cnt = w - r;
217         } else {
218                 free_cnt = (w - r + size) & size_mask;
219         }
220
221         cnt2 = r + free_cnt;
222
223         if (cnt2 > size) {
224                 /* Two part vector: the rest of the buffer after the
225                    current write ptr, plus some from the start of 
226                    the buffer.
227                 */
228
229                 vec->buf[0] = &buf[r];
230                 vec->len[0] = size - r;
231                 vec->buf[1] = buf;
232                 vec->len[1] = cnt2 & size_mask;
233
234         } else {
235                 
236                 /* Single part vector: just the rest of the buffer */
237                 
238                 vec->buf[0] = &buf[r];
239                 vec->len[0] = free_cnt;
240                 vec->len[1] = 0;
241         }
242 }
243
244 template<class T> void
245 RingBuffer<T>::get_write_vector (RingBuffer<T>::rw_vector *vec)
246
247 {
248         size_t free_cnt;
249         size_t cnt2;
250         size_t w, r;
251         
252         w = g_atomic_int_get (&write_ptr);
253         r = g_atomic_int_get (&read_ptr);
254         
255         if (w > r) {
256                 free_cnt = ((r - w + size) & size_mask) - 1;
257         } else if (w < r) {
258                 free_cnt = (r - w) - 1;
259         } else {
260                 free_cnt = size - 1;
261         }
262         
263         cnt2 = w + free_cnt;
264
265         if (cnt2 > size) {
266                 
267                 /* Two part vector: the rest of the buffer after the
268                    current write ptr, plus some from the start of 
269                    the buffer.
270                 */
271
272                 vec->buf[0] = &buf[w];
273                 vec->len[0] = size - w;
274                 vec->buf[1] = buf;
275                 vec->len[1] = cnt2 & size_mask;
276         } else {
277                 vec->buf[0] = &buf[w];
278                 vec->len[0] = free_cnt;
279                 vec->len[1] = 0;
280         }
281 }
282
283
284 #endif /* __ringbuffer_h__ */