Cinder  0.8.6
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
RingBuffer.h
Go to the documentation of this file.
1 /*
2  Copyright (c) 2014, The Cinder Project
3 
4  This code is intended to be used with the Cinder C++ library, http://libcinder.org
5 
6  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
7  the following conditions are met:
8 
9  * Redistributions of source code must retain the above copyright notice, this list of conditions and
10  the following disclaimer.
11  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
12  the following disclaimer in the documentation and/or other materials provided with the distribution.
13 
14  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
15  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
16  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
17  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
18  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21  POSSIBILITY OF SUCH DAMAGE.
22 */
23 
24 #pragma once
25 
26 #include "cinder/CinderAssert.h"
27 
28 #include <atomic>
29 
30 namespace cinder { namespace audio { namespace dsp {
31 
41 template <typename T>
42 class RingBufferT {
43  public:
45  RingBufferT() : mData( nullptr ), mAllocatedSize( 0 ), mWriteIndex( 0 ), mReadIndex( 0 ) {}
47  RingBufferT( size_t count ) : mAllocatedSize( 0 )
48  {
49  resize( count );
50  }
51 
53  : mData( other.mData ), mAllocatedSize( other.mAllocatedSize ), mWriteIndex( 0 ), mReadIndex( 0 )
54  {
55  other.mData = nullptr;
56  other.mAllocatedSize = 0;
57  }
58 
60  {
61  if( mData )
62  free( mData );
63  }
65  void resize( size_t count )
66  {
67  size_t allocatedSize = count + 1; // one bin is used to distinguish between the read and write indices when full.
68 
69  if( mAllocatedSize )
70  mData = (T *)::realloc( mData, allocatedSize * sizeof( T ) );
71  else
72  mData = (T *)::calloc( allocatedSize, sizeof( T ) );
73 
74  CI_ASSERT( mData );
75 
76  mAllocatedSize = allocatedSize;
77  clear();
78  }
80  void clear()
81  {
82  mWriteIndex = 0;
83  mReadIndex = 0;
84  }
86  size_t getSize() const
87  {
88  return mAllocatedSize - 1;
89  }
91  size_t getAvailableWrite() const
92  {
93  return getAvailableWrite( mWriteIndex, mReadIndex );
94  }
96  size_t getAvailableRead() const
97  {
98  return getAvailableRead( mWriteIndex, mReadIndex );
99  }
100 
105  bool write( const T *array, size_t count )
106  {
107  const size_t writeIndex = mWriteIndex.load( std::memory_order_relaxed );
108  const size_t readIndex = mReadIndex.load( std::memory_order_acquire );
109 
110  if( count > getAvailableWrite( writeIndex, readIndex ) )
111  return false;
112 
113  size_t writeIndexAfter = writeIndex + count;
114 
115  if( writeIndex + count > mAllocatedSize ) {
116  size_t countA = mAllocatedSize - writeIndex;
117  size_t countB = count - countA;
118 
119  std::memcpy( mData + writeIndex, array, countA * sizeof( T ) );
120  std::memcpy( mData, array + countA, countB * sizeof( T ) );
121  writeIndexAfter -= mAllocatedSize;
122  }
123  else {
124  std::memcpy( mData + writeIndex, array, count * sizeof( T ) );
125  if( writeIndexAfter == mAllocatedSize )
126  writeIndexAfter = 0;
127  }
128 
129  mWriteIndex.store( writeIndexAfter, std::memory_order_release );
130  return true;
131  }
135  bool read( T *array, size_t count )
136  {
137  const size_t writeIndex = mWriteIndex.load( std::memory_order_acquire );
138  const size_t readIndex = mReadIndex.load( std::memory_order_relaxed );
139 
140  if( count > getAvailableRead( writeIndex, readIndex ) )
141  return false;
142 
143  size_t readIndexAfter = readIndex + count;
144 
145  if( readIndex + count > mAllocatedSize ) {
146  size_t countA = mAllocatedSize - readIndex;
147  size_t countB = count - countA;
148 
149  std::memcpy( array, mData + readIndex, countA * sizeof( T ) );
150  std::memcpy( array + countA, mData, countB * sizeof( T ) );
151 
152  readIndexAfter -= mAllocatedSize;
153  }
154  else {
155  std::memcpy( array, mData + readIndex, count * sizeof( T ) );
156  if( readIndexAfter == mAllocatedSize )
157  readIndexAfter = 0;
158  }
159 
160  mReadIndex.store( readIndexAfter, std::memory_order_release );
161  return true;
162  }
163 
164  private:
165  size_t getAvailableWrite( size_t writeIndex, size_t readIndex ) const
166  {
167  size_t result = readIndex - writeIndex - 1;
168  if( writeIndex >= readIndex )
169  result += mAllocatedSize;
170 
171  return result;
172  }
173 
174  size_t getAvailableRead( size_t writeIndex, size_t readIndex ) const
175  {
176  if( writeIndex >= readIndex )
177  return writeIndex - readIndex;
178 
179  return writeIndex + mAllocatedSize - readIndex;
180  }
181 
182 
183  T *mData;
184  size_t mAllocatedSize;
185  std::atomic<size_t> mWriteIndex, mReadIndex;
186 };
187 
189 
190 } } } // namespace cinder::audio::dsp
void resize(size_t count)
Resizes the container to contain count maximum elements. Invalidates the internal buffer and resets r...
Definition: RingBuffer.h:65
bool read(T *array, size_t count)
Reads count elements from the internal buffer into array.
Definition: RingBuffer.h:135
void clear()
Invalidates the internal buffer and resets read / write indices to 0.
Definition: RingBuffer.h:80
Ringbuffer (aka circular buffer) data structure for use in concurrent audio scenarios.
Definition: RingBuffer.h:42
RingBufferT< float > RingBuffer
Definition: RingBuffer.h:188
size_t getAvailableWrite() const
Returns the number of elements available for wrtiing.
Definition: RingBuffer.h:91
~RingBufferT()
Definition: RingBuffer.h:59
GLuint GLuint GLsizei count
Definition: GLee.h:963
size_t getSize() const
Returns the maximum number of elements.
Definition: RingBuffer.h:86
RingBufferT(size_t count)
Constructs a RingBufferT with count maximum elements.
Definition: RingBuffer.h:47
RingBufferT()
Constructs a RingBufferT with size = 0.
Definition: RingBuffer.h:45
bool write(const T *array, size_t count)
Writes count elements into the internal buffer from array.
Definition: RingBuffer.h:105
RingBufferT(RingBufferT &&other)
Definition: RingBuffer.h:52
size_t getAvailableRead() const
Returns the number of elements available for wrtiing.
Definition: RingBuffer.h:96
#define CI_ASSERT(expr)
Definition: CinderAssert.h:75