annotate base/RingBuffer.h @ 575:8688430850d6

* either I'm going mad or the compiler is... valgrind and sizeof both seem to think that reading or writing m_size is reading beyond the end of the object, unless I add m_spare padding... why?
author Chris Cannam
date Mon, 16 Mar 2009 16:32:02 +0000
parents 2d551c765d51
children 2ba202c5be8d
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@0 7
Chris@52 8 This program is free software; you can redistribute it and/or
Chris@52 9 modify it under the terms of the GNU General Public License as
Chris@52 10 published by the Free Software Foundation; either version 2 of the
Chris@52 11 License, or (at your option) any later version. See the file
Chris@52 12 COPYING included with this distribution for more information.
Chris@0 13 */
Chris@0 14
Chris@0 15 /*
Chris@0 16 This is a modified version of a source file from the
Chris@0 17 Rosegarden MIDI and audio sequencer and notation editor.
Chris@17 18 This file copyright 2000-2006 Chris Cannam.
Chris@0 19 */
Chris@0 20
Chris@0 21 #ifndef _RINGBUFFER_H_
Chris@0 22 #define _RINGBUFFER_H_
Chris@0 23
Chris@0 24 #include <sys/types.h>
Chris@0 25
Chris@150 26 #include "system/System.h"
Chris@0 27 #include "Scavenger.h"
Chris@0 28
Chris@485 29 #include <cstring> // memcpy, memset &c
Chris@485 30
Chris@0 31 //#define DEBUG_RINGBUFFER 1
Chris@0 32
Chris@0 33 #ifdef DEBUG_RINGBUFFER
Chris@0 34 #include <iostream>
Chris@0 35 #endif
Chris@0 36
Chris@0 37 /**
Chris@0 38 * RingBuffer implements a lock-free ring buffer for one writer and N
Chris@0 39 * readers, that is to be used to store a sample type T.
Chris@0 40 *
Chris@0 41 * For efficiency, RingBuffer frequently initialises samples by
Chris@0 42 * writing zeroes into their memory space, so T should normally be a
Chris@0 43 * simple type that can safely be set to zero using memset.
Chris@0 44 */
Chris@0 45
Chris@0 46 template <typename T, int N = 1>
Chris@0 47 class RingBuffer
Chris@0 48 {
Chris@0 49 public:
Chris@0 50 /**
Chris@0 51 * Create a ring buffer with room to write n samples.
Chris@0 52 *
Chris@0 53 * Note that the internal storage size will actually be n+1
Chris@0 54 * samples, as one element is unavailable for administrative
Chris@0 55 * reasons. Since the ring buffer performs best if its size is a
Chris@0 56 * power of two, this means n should ideally be some power of two
Chris@0 57 * minus one.
Chris@0 58 */
Chris@0 59 RingBuffer(size_t n);
Chris@0 60
Chris@0 61 virtual ~RingBuffer();
Chris@0 62
Chris@0 63 /**
Chris@0 64 * Return the total capacity of the ring buffer in samples.
Chris@0 65 * (This is the argument n passed to the constructor.)
Chris@0 66 */
Chris@0 67 size_t getSize() const;
Chris@0 68
Chris@0 69 /**
Chris@0 70 * Resize the ring buffer. This also empties it. Actually swaps
Chris@0 71 * in a new, larger buffer; the old buffer is scavenged after a
Chris@0 72 * seemly delay. Should be called from the write thread.
Chris@0 73 */
Chris@0 74 void resize(size_t newSize);
Chris@0 75
Chris@0 76 /**
Chris@0 77 * Lock the ring buffer into physical memory. Returns true
Chris@0 78 * for success.
Chris@0 79 */
Chris@0 80 bool mlock();
Chris@0 81
Chris@0 82 /**
Chris@0 83 * Reset read and write pointers, thus emptying the buffer.
Chris@0 84 * Should be called from the write thread.
Chris@0 85 */
Chris@0 86 void reset();
Chris@0 87
Chris@0 88 /**
Chris@0 89 * Return the amount of data available for reading by reader R, in
Chris@0 90 * samples.
Chris@0 91 */
Chris@0 92 size_t getReadSpace(int R = 0) const;
Chris@0 93
Chris@0 94 /**
Chris@0 95 * Return the amount of space available for writing, in samples.
Chris@0 96 */
Chris@0 97 size_t getWriteSpace() const;
Chris@0 98
Chris@0 99 /**
Chris@0 100 * Read n samples from the buffer, for reader R. If fewer than n
Chris@0 101 * are available, the remainder will be zeroed out. Returns the
Chris@0 102 * number of samples actually read.
Chris@0 103 */
Chris@0 104 size_t read(T *destination, size_t n, int R = 0);
Chris@0 105
Chris@0 106 /**
Chris@0 107 * Read n samples from the buffer, for reader R, adding them to
Chris@0 108 * the destination. If fewer than n are available, the remainder
Chris@0 109 * will be left alone. Returns the number of samples actually
Chris@0 110 * read.
Chris@0 111 */
Chris@0 112 size_t readAdding(T *destination, size_t n, int R = 0);
Chris@0 113
Chris@0 114 /**
Chris@0 115 * Read one sample from the buffer, for reader R. If no sample is
Chris@0 116 * available, this will silently return zero. Calling this
Chris@0 117 * repeatedly is obviously slower than calling read once, but it
Chris@0 118 * may be good enough if you don't want to allocate a buffer to
Chris@0 119 * read into.
Chris@0 120 */
Chris@0 121 T readOne(int R = 0);
Chris@0 122
Chris@0 123 /**
Chris@0 124 * Read n samples from the buffer, if available, for reader R,
Chris@0 125 * without advancing the read pointer -- i.e. a subsequent read()
Chris@0 126 * or skip() will be necessary to empty the buffer. If fewer than
Chris@0 127 * n are available, the remainder will be zeroed out. Returns the
Chris@0 128 * number of samples actually read.
Chris@0 129 */
Chris@0 130 size_t peek(T *destination, size_t n, int R = 0) const;
Chris@0 131
Chris@0 132 /**
Chris@0 133 * Read one sample from the buffer, if available, without
Chris@0 134 * advancing the read pointer -- i.e. a subsequent read() or
Chris@0 135 * skip() will be necessary to empty the buffer. Returns zero if
Chris@0 136 * no sample was available.
Chris@0 137 */
Chris@0 138 T peekOne(int R = 0) const;
Chris@0 139
Chris@0 140 /**
Chris@0 141 * Pretend to read n samples from the buffer, for reader R,
Chris@0 142 * without actually returning them (i.e. discard the next n
Chris@0 143 * samples). Returns the number of samples actually available for
Chris@0 144 * discarding.
Chris@0 145 */
Chris@0 146 size_t skip(size_t n, int R = 0);
Chris@0 147
Chris@0 148 /**
Chris@0 149 * Write n samples to the buffer. If insufficient space is
Chris@0 150 * available, not all samples may actually be written. Returns
Chris@0 151 * the number of samples actually written.
Chris@0 152 */
Chris@0 153 size_t write(const T *source, size_t n);
Chris@0 154
Chris@0 155 /**
Chris@0 156 * Write n zero-value samples to the buffer. If insufficient
Chris@0 157 * space is available, not all zeros may actually be written.
Chris@0 158 * Returns the number of zeroes actually written.
Chris@0 159 */
Chris@0 160 size_t zero(size_t n);
Chris@0 161
Chris@0 162 protected:
Chris@574 163 T *m_buffer;
Chris@574 164 bool m_mlocked;
Chris@574 165 size_t m_writer;
Chris@574 166 size_t *m_readers;
Chris@574 167 size_t m_size;
Chris@575 168 size_t m_spare;
Chris@0 169
Chris@0 170 static Scavenger<ScavengerArrayWrapper<T> > m_scavenger;
Chris@0 171
Chris@0 172 private:
Chris@0 173 RingBuffer(const RingBuffer &); // not provided
Chris@0 174 RingBuffer &operator=(const RingBuffer &); // not provided
Chris@0 175 };
Chris@0 176
Chris@0 177 template <typename T, int N>
Chris@0 178 Scavenger<ScavengerArrayWrapper<T> > RingBuffer<T, N>::m_scavenger;
Chris@0 179
Chris@0 180 template <typename T, int N>
Chris@0 181 RingBuffer<T, N>::RingBuffer(size_t n) :
Chris@0 182 m_buffer(new T[n + 1]),
Chris@574 183 m_mlocked(false),
Chris@0 184 m_writer(0),
Chris@574 185 m_readers(new size_t[N]),
Chris@574 186 m_size(n + 1)
Chris@0 187 {
Chris@0 188 #ifdef DEBUG_RINGBUFFER
Chris@0 189 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::RingBuffer(" << n << ")" << std::endl;
Chris@0 190 #endif
Chris@575 191 /*
Chris@575 192 std::cerr << "note: sizeof(RingBuffer<T,N> = " << sizeof(RingBuffer<T,N>) << ")" << std::endl;
Chris@0 193
Chris@575 194 std::cerr << "this = " << this << std::endl;
Chris@575 195 std::cerr << "&m_buffer = " << &m_buffer << std::endl;
Chris@575 196 std::cerr << "&m_mlocked = " << &m_mlocked << std::endl;
Chris@575 197 std::cerr << "&m_writer = " << &m_writer << std::endl;
Chris@575 198 std::cerr << "&m_readers = " << &m_readers << std::endl;
Chris@575 199 std::cerr << "&m_size = " << &m_size << std::endl;
Chris@575 200 */
Chris@0 201 for (int i = 0; i < N; ++i) m_readers[i] = 0;
Chris@0 202
Chris@0 203 m_scavenger.scavenge();
Chris@0 204 }
Chris@0 205
Chris@0 206 template <typename T, int N>
Chris@0 207 RingBuffer<T, N>::~RingBuffer()
Chris@0 208 {
Chris@0 209 #ifdef DEBUG_RINGBUFFER
Chris@0 210 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::~RingBuffer" << std::endl;
Chris@0 211 #endif
Chris@0 212
Chris@574 213 delete[] m_readers;
Chris@574 214
Chris@0 215 if (m_mlocked) {
Chris@0 216 MUNLOCK((void *)m_buffer, m_size * sizeof(T));
Chris@0 217 }
Chris@0 218 delete[] m_buffer;
Chris@0 219
Chris@0 220 m_scavenger.scavenge();
Chris@0 221 }
Chris@0 222
Chris@0 223 template <typename T, int N>
Chris@0 224 size_t
Chris@0 225 RingBuffer<T, N>::getSize() const
Chris@0 226 {
Chris@0 227 #ifdef DEBUG_RINGBUFFER
Chris@0 228 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getSize(): " << m_size-1 << std::endl;
Chris@0 229 #endif
Chris@0 230
Chris@0 231 return m_size - 1;
Chris@0 232 }
Chris@0 233
Chris@0 234 template <typename T, int N>
Chris@0 235 void
Chris@0 236 RingBuffer<T, N>::resize(size_t newSize)
Chris@0 237 {
Chris@0 238 #ifdef DEBUG_RINGBUFFER
Chris@0 239 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::resize(" << newSize << ")" << std::endl;
Chris@0 240 #endif
Chris@0 241
Chris@0 242 m_scavenger.scavenge();
Chris@0 243
Chris@0 244 if (m_mlocked) {
Chris@0 245 MUNLOCK((void *)m_buffer, m_size * sizeof(T));
Chris@0 246 }
Chris@0 247
Chris@0 248 m_scavenger.claim(new ScavengerArrayWrapper<T>(m_buffer));
Chris@0 249
Chris@0 250 reset();
Chris@0 251 m_buffer = new T[newSize + 1];
Chris@0 252 m_size = newSize + 1;
Chris@0 253
Chris@0 254 if (m_mlocked) {
Chris@0 255 if (MLOCK((void *)m_buffer, m_size * sizeof(T))) {
Chris@0 256 m_mlocked = false;
Chris@0 257 }
Chris@0 258 }
Chris@0 259 }
Chris@0 260
Chris@0 261 template <typename T, int N>
Chris@0 262 bool
Chris@0 263 RingBuffer<T, N>::mlock()
Chris@0 264 {
Chris@0 265 if (MLOCK((void *)m_buffer, m_size * sizeof(T))) return false;
Chris@0 266 m_mlocked = true;
Chris@0 267 return true;
Chris@0 268 }
Chris@0 269
Chris@0 270 template <typename T, int N>
Chris@0 271 void
Chris@0 272 RingBuffer<T, N>::reset()
Chris@0 273 {
Chris@0 274 #ifdef DEBUG_RINGBUFFER
Chris@0 275 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::reset" << std::endl;
Chris@0 276 #endif
Chris@0 277
Chris@0 278 m_writer = 0;
Chris@0 279 for (int i = 0; i < N; ++i) m_readers[i] = 0;
Chris@0 280 }
Chris@0 281
Chris@0 282 template <typename T, int N>
Chris@0 283 size_t
Chris@0 284 RingBuffer<T, N>::getReadSpace(int R) const
Chris@0 285 {
Chris@0 286 size_t writer = m_writer;
Chris@0 287 size_t reader = m_readers[R];
Chris@0 288 size_t space = 0;
Chris@0 289
Chris@0 290 if (writer > reader) space = writer - reader;
Chris@0 291 else space = ((writer + m_size) - reader) % m_size;
Chris@0 292
Chris@0 293 #ifdef DEBUG_RINGBUFFER
Chris@0 294 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getReadSpace(" << R << "): " << space << std::endl;
Chris@0 295 #endif
Chris@0 296
Chris@0 297 return space;
Chris@0 298 }
Chris@0 299
Chris@0 300 template <typename T, int N>
Chris@0 301 size_t
Chris@0 302 RingBuffer<T, N>::getWriteSpace() const
Chris@0 303 {
Chris@0 304 size_t space = 0;
Chris@0 305 for (int i = 0; i < N; ++i) {
Chris@0 306 size_t here = (m_readers[i] + m_size - m_writer - 1) % m_size;
Chris@0 307 if (i == 0 || here < space) space = here;
Chris@0 308 }
Chris@0 309
Chris@0 310 #ifdef DEBUG_RINGBUFFER
Chris@0 311 size_t rs(getReadSpace()), rp(m_readers[0]);
Chris@0 312
Chris@0 313 std::cerr << "RingBuffer: write space " << space << ", read space "
Chris@0 314 << rs << ", total " << (space + rs) << ", m_size " << m_size << std::endl;
Chris@0 315 std::cerr << "RingBuffer: reader " << rp << ", writer " << m_writer << std::endl;
Chris@0 316 #endif
Chris@0 317
Chris@0 318 #ifdef DEBUG_RINGBUFFER
Chris@0 319 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getWriteSpace(): " << space << std::endl;
Chris@0 320 #endif
Chris@0 321
Chris@0 322 return space;
Chris@0 323 }
Chris@0 324
Chris@0 325 template <typename T, int N>
Chris@0 326 size_t
Chris@0 327 RingBuffer<T, N>::read(T *destination, size_t n, int R)
Chris@0 328 {
Chris@0 329 #ifdef DEBUG_RINGBUFFER
Chris@0 330 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read(dest, " << n << ", " << R << ")" << std::endl;
Chris@0 331 #endif
Chris@0 332
Chris@0 333 size_t available = getReadSpace(R);
Chris@0 334 if (n > available) {
Chris@0 335 #ifdef DEBUG_RINGBUFFER
Chris@0 336 std::cerr << "WARNING: Only " << available << " samples available"
Chris@0 337 << std::endl;
Chris@0 338 #endif
Chris@0 339 memset(destination + available, 0, (n - available) * sizeof(T));
Chris@0 340 n = available;
Chris@0 341 }
Chris@0 342 if (n == 0) return n;
Chris@0 343
Chris@0 344 size_t here = m_size - m_readers[R];
Chris@0 345 if (here >= n) {
Chris@0 346 memcpy(destination, m_buffer + m_readers[R], n * sizeof(T));
Chris@0 347 } else {
Chris@0 348 memcpy(destination, m_buffer + m_readers[R], here * sizeof(T));
Chris@0 349 memcpy(destination + here, m_buffer, (n - here) * sizeof(T));
Chris@0 350 }
Chris@0 351
Chris@0 352 m_readers[R] = (m_readers[R] + n) % m_size;
Chris@0 353
Chris@0 354 #ifdef DEBUG_RINGBUFFER
Chris@0 355 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read: read " << n << ", reader now " << m_readers[R] << std::endl;
Chris@0 356 #endif
Chris@0 357
Chris@0 358 return n;
Chris@0 359 }
Chris@0 360
Chris@0 361 template <typename T, int N>
Chris@0 362 size_t
Chris@0 363 RingBuffer<T, N>::readAdding(T *destination, size_t n, int R)
Chris@0 364 {
Chris@0 365 #ifdef DEBUG_RINGBUFFER
Chris@0 366 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readAdding(dest, " << n << ", " << R << ")" << std::endl;
Chris@0 367 #endif
Chris@0 368
Chris@0 369 size_t available = getReadSpace(R);
Chris@0 370 if (n > available) {
Chris@0 371 #ifdef DEBUG_RINGBUFFER
Chris@0 372 std::cerr << "WARNING: Only " << available << " samples available"
Chris@0 373 << std::endl;
Chris@0 374 #endif
Chris@0 375 n = available;
Chris@0 376 }
Chris@0 377 if (n == 0) return n;
Chris@0 378
Chris@0 379 size_t here = m_size - m_readers[R];
Chris@0 380
Chris@0 381 if (here >= n) {
Chris@0 382 for (size_t i = 0; i < n; ++i) {
Chris@0 383 destination[i] += (m_buffer + m_readers[R])[i];
Chris@0 384 }
Chris@0 385 } else {
Chris@0 386 for (size_t i = 0; i < here; ++i) {
Chris@0 387 destination[i] += (m_buffer + m_readers[R])[i];
Chris@0 388 }
Chris@0 389 for (size_t i = 0; i < (n - here); ++i) {
Chris@0 390 destination[i + here] += m_buffer[i];
Chris@0 391 }
Chris@0 392 }
Chris@0 393
Chris@0 394 m_readers[R] = (m_readers[R] + n) % m_size;
Chris@0 395 return n;
Chris@0 396 }
Chris@0 397
Chris@0 398 template <typename T, int N>
Chris@0 399 T
Chris@0 400 RingBuffer<T, N>::readOne(int R)
Chris@0 401 {
Chris@0 402 #ifdef DEBUG_RINGBUFFER
Chris@0 403 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readOne(" << R << ")" << std::endl;
Chris@0 404 #endif
Chris@0 405
Chris@0 406 if (m_writer == m_readers[R]) {
Chris@0 407 #ifdef DEBUG_RINGBUFFER
Chris@0 408 std::cerr << "WARNING: No sample available"
Chris@0 409 << std::endl;
Chris@0 410 #endif
Chris@0 411 T t;
Chris@0 412 memset(&t, 0, sizeof(T));
Chris@0 413 return t;
Chris@0 414 }
Chris@0 415 T value = m_buffer[m_readers[R]];
Chris@0 416 if (++m_readers[R] == m_size) m_readers[R] = 0;
Chris@0 417 return value;
Chris@0 418 }
Chris@0 419
Chris@0 420 template <typename T, int N>
Chris@0 421 size_t
Chris@0 422 RingBuffer<T, N>::peek(T *destination, size_t n, int R) const
Chris@0 423 {
Chris@0 424 #ifdef DEBUG_RINGBUFFER
Chris@0 425 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(dest, " << n << ", " << R << ")" << std::endl;
Chris@0 426 #endif
Chris@0 427
Chris@0 428 size_t available = getReadSpace(R);
Chris@0 429 if (n > available) {
Chris@0 430 #ifdef DEBUG_RINGBUFFER
Chris@0 431 std::cerr << "WARNING: Only " << available << " samples available"
Chris@0 432 << std::endl;
Chris@0 433 #endif
Chris@0 434 memset(destination + available, 0, (n - available) * sizeof(T));
Chris@0 435 n = available;
Chris@0 436 }
Chris@0 437 if (n == 0) return n;
Chris@0 438
Chris@0 439 size_t here = m_size - m_readers[R];
Chris@0 440 if (here >= n) {
Chris@0 441 memcpy(destination, m_buffer + m_readers[R], n * sizeof(T));
Chris@0 442 } else {
Chris@0 443 memcpy(destination, m_buffer + m_readers[R], here * sizeof(T));
Chris@0 444 memcpy(destination + here, m_buffer, (n - here) * sizeof(T));
Chris@0 445 }
Chris@0 446
Chris@0 447 #ifdef DEBUG_RINGBUFFER
Chris@0 448 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek: read " << n << std::endl;
Chris@0 449 #endif
Chris@0 450
Chris@0 451 return n;
Chris@0 452 }
Chris@0 453
Chris@0 454 template <typename T, int N>
Chris@0 455 T
Chris@0 456 RingBuffer<T, N>::peekOne(int R) const
Chris@0 457 {
Chris@0 458 #ifdef DEBUG_RINGBUFFER
Chris@0 459 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(" << R << ")" << std::endl;
Chris@0 460 #endif
Chris@0 461
Chris@0 462 if (m_writer == m_readers[R]) {
Chris@0 463 #ifdef DEBUG_RINGBUFFER
Chris@0 464 std::cerr << "WARNING: No sample available"
Chris@0 465 << std::endl;
Chris@0 466 #endif
Chris@0 467 T t;
Chris@0 468 memset(&t, 0, sizeof(T));
Chris@0 469 return t;
Chris@0 470 }
Chris@0 471 T value = m_buffer[m_readers[R]];
Chris@0 472 return value;
Chris@0 473 }
Chris@0 474
Chris@0 475 template <typename T, int N>
Chris@0 476 size_t
Chris@0 477 RingBuffer<T, N>::skip(size_t n, int R)
Chris@0 478 {
Chris@0 479 #ifdef DEBUG_RINGBUFFER
Chris@0 480 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::skip(" << n << ", " << R << ")" << std::endl;
Chris@0 481 #endif
Chris@0 482
Chris@0 483 size_t available = getReadSpace(R);
Chris@0 484 if (n > available) {
Chris@0 485 #ifdef DEBUG_RINGBUFFER
Chris@0 486 std::cerr << "WARNING: Only " << available << " samples available"
Chris@0 487 << std::endl;
Chris@0 488 #endif
Chris@0 489 n = available;
Chris@0 490 }
Chris@0 491 if (n == 0) return n;
Chris@0 492 m_readers[R] = (m_readers[R] + n) % m_size;
Chris@0 493 return n;
Chris@0 494 }
Chris@0 495
Chris@0 496 template <typename T, int N>
Chris@0 497 size_t
Chris@0 498 RingBuffer<T, N>::write(const T *source, size_t n)
Chris@0 499 {
Chris@0 500 #ifdef DEBUG_RINGBUFFER
Chris@0 501 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write(" << n << ")" << std::endl;
Chris@0 502 #endif
Chris@0 503
Chris@0 504 size_t available = getWriteSpace();
Chris@0 505 if (n > available) {
Chris@0 506 #ifdef DEBUG_RINGBUFFER
Chris@0 507 std::cerr << "WARNING: Only room for " << available << " samples"
Chris@0 508 << std::endl;
Chris@0 509 #endif
Chris@0 510 n = available;
Chris@0 511 }
Chris@0 512 if (n == 0) return n;
Chris@0 513
Chris@0 514 size_t here = m_size - m_writer;
Chris@0 515 if (here >= n) {
Chris@0 516 memcpy(m_buffer + m_writer, source, n * sizeof(T));
Chris@0 517 } else {
Chris@0 518 memcpy(m_buffer + m_writer, source, here * sizeof(T));
Chris@0 519 memcpy(m_buffer, source + here, (n - here) * sizeof(T));
Chris@0 520 }
Chris@0 521
Chris@0 522 m_writer = (m_writer + n) % m_size;
Chris@0 523
Chris@0 524 #ifdef DEBUG_RINGBUFFER
Chris@0 525 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write: wrote " << n << ", writer now " << m_writer << std::endl;
Chris@0 526 #endif
Chris@0 527
Chris@0 528 return n;
Chris@0 529 }
Chris@0 530
Chris@0 531 template <typename T, int N>
Chris@0 532 size_t
Chris@0 533 RingBuffer<T, N>::zero(size_t n)
Chris@0 534 {
Chris@0 535 #ifdef DEBUG_RINGBUFFER
Chris@0 536 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::zero(" << n << ")" << std::endl;
Chris@0 537 #endif
Chris@0 538
Chris@0 539 size_t available = getWriteSpace();
Chris@0 540 if (n > available) {
Chris@0 541 #ifdef DEBUG_RINGBUFFER
Chris@0 542 std::cerr << "WARNING: Only room for " << available << " samples"
Chris@0 543 << std::endl;
Chris@0 544 #endif
Chris@0 545 n = available;
Chris@0 546 }
Chris@0 547 if (n == 0) return n;
Chris@0 548
Chris@0 549 size_t here = m_size - m_writer;
Chris@0 550 if (here >= n) {
Chris@0 551 memset(m_buffer + m_writer, 0, n * sizeof(T));
Chris@0 552 } else {
Chris@0 553 memset(m_buffer + m_writer, 0, here * sizeof(T));
Chris@0 554 memset(m_buffer, 0, (n - here) * sizeof(T));
Chris@0 555 }
Chris@0 556
Chris@0 557 m_writer = (m_writer + n) % m_size;
Chris@0 558 return n;
Chris@0 559 }
Chris@0 560
Chris@0 561 #endif // _RINGBUFFER_H_