OpenShot Library | libopenshot-audio  0.2.0
juce_AbstractFifo.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
26 AbstractFifo::AbstractFifo (int capacity) noexcept : bufferSize (capacity)
27 {
28  jassert (bufferSize > 0);
29 }
30 
32 
33 int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
34 int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady() - 1; }
35 
36 int AbstractFifo::getNumReady() const noexcept
37 {
38  auto vs = validStart.get();
39  auto ve = validEnd.get();
40  return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
41 }
42 
43 void AbstractFifo::reset() noexcept
44 {
45  validEnd = 0;
46  validStart = 0;
47 }
48 
49 void AbstractFifo::setTotalSize (int newSize) noexcept
50 {
51  jassert (newSize > 0);
52  reset();
53  bufferSize = newSize;
54 }
55 
56 //==============================================================================
57 void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1,
58  int& startIndex2, int& blockSize2) const noexcept
59 {
60  auto vs = validStart.get();
61  auto ve = validEnd.get();
62 
63  auto freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve);
64  numToWrite = jmin (numToWrite, freeSpace - 1);
65 
66  if (numToWrite <= 0)
67  {
68  startIndex1 = 0;
69  startIndex2 = 0;
70  blockSize1 = 0;
71  blockSize2 = 0;
72  }
73  else
74  {
75  startIndex1 = ve;
76  startIndex2 = 0;
77  blockSize1 = jmin (bufferSize - ve, numToWrite);
78  numToWrite -= blockSize1;
79  blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, vs);
80  }
81 }
82 
83 void AbstractFifo::finishedWrite (int numWritten) noexcept
84 {
85  jassert (numWritten >= 0 && numWritten < bufferSize);
86 
87  auto newEnd = validEnd.get() + numWritten;
88 
89  if (newEnd >= bufferSize)
90  newEnd -= bufferSize;
91 
92  validEnd = newEnd;
93 }
94 
95 void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1,
96  int& startIndex2, int& blockSize2) const noexcept
97 {
98  auto vs = validStart.get();
99  auto ve = validEnd.get();
100 
101  auto numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
102  numWanted = jmin (numWanted, numReady);
103 
104  if (numWanted <= 0)
105  {
106  startIndex1 = 0;
107  startIndex2 = 0;
108  blockSize1 = 0;
109  blockSize2 = 0;
110  }
111  else
112  {
113  startIndex1 = vs;
114  startIndex2 = 0;
115  blockSize1 = jmin (bufferSize - vs, numWanted);
116  numWanted -= blockSize1;
117  blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, ve);
118  }
119 }
120 
121 void AbstractFifo::finishedRead (int numRead) noexcept
122 {
123  jassert (numRead >= 0 && numRead <= bufferSize);
124 
125  auto newStart = validStart.get() + numRead;
126 
127  if (newStart >= bufferSize)
128  newStart -= bufferSize;
129 
130  validStart = newStart;
131 }
132 
133 //==============================================================================
134 template <AbstractFifo::ReadOrWrite mode>
136  : startIndex1 (other.startIndex1),
137  blockSize1 (other.blockSize1),
138  startIndex2 (other.startIndex2),
139  blockSize2 (other.blockSize2)
140 {
141  swap (other);
142 }
143 
144 template <AbstractFifo::ReadOrWrite mode>
147 {
148  swap (other);
149  return *this;
150 }
151 
152 template <AbstractFifo::ReadOrWrite mode>
154 {
155  std::swap (other.fifo, fifo);
156  std::swap (other.startIndex1, startIndex1);
157  std::swap (other.blockSize1, blockSize1);
158  std::swap (other.startIndex2, startIndex2);
159  std::swap (other.blockSize2, blockSize2);
160 }
161 
164 
165 AbstractFifo::ScopedRead AbstractFifo::read (int numToRead) noexcept { return { *this, numToRead }; }
166 AbstractFifo::ScopedWrite AbstractFifo::write (int numToWrite) noexcept { return { *this, numToWrite }; }
167 
168 
169 //==============================================================================
170 #if JUCE_UNIT_TESTS
171 
172 class AbstractFifoTests : public UnitTest
173 {
174 public:
175  AbstractFifoTests() : UnitTest ("Abstract Fifo", "Containers") {}
176 
177  struct WriteThread : public Thread
178  {
179  WriteThread (AbstractFifo& f, int* b, Random rng)
180  : Thread ("fifo writer"), fifo (f), buffer (b), random (rng)
181  {
182  startThread();
183  }
184 
185  ~WriteThread()
186  {
187  stopThread (5000);
188  }
189 
190  void run()
191  {
192  int n = 0;
193 
194  while (! threadShouldExit())
195  {
196  int num = random.nextInt (2000) + 1;
197 
198  auto writer = fifo.write (num);
199 
200  jassert (writer.blockSize1 >= 0 && writer.blockSize2 >= 0);
201  jassert (writer.blockSize1 == 0
202  || (writer.startIndex1 >= 0 && writer.startIndex1 < fifo.getTotalSize()));
203  jassert (writer.blockSize2 == 0
204  || (writer.startIndex2 >= 0 && writer.startIndex2 < fifo.getTotalSize()));
205 
206  writer.forEach ([this, &n] (int index) { this->buffer[index] = n++; });
207  }
208  }
209 
210  AbstractFifo& fifo;
211  int* buffer;
212  Random random;
213  };
214 
215  void runTest() override
216  {
217  beginTest ("AbstractFifo");
218 
219  int buffer[5000];
220  AbstractFifo fifo (numElementsInArray (buffer));
221 
222  WriteThread writer (fifo, buffer, getRandom());
223 
224  int n = 0;
225  Random r = getRandom();
226  r.combineSeed (12345);
227 
228  for (int count = 100000; --count >= 0;)
229  {
230  int num = r.nextInt (6000) + 1;
231 
232  auto reader = fifo.read (num);
233 
234  if (! (reader.blockSize1 >= 0 && reader.blockSize2 >= 0)
235  && (reader.blockSize1 == 0
236  || (reader.startIndex1 >= 0 && reader.startIndex1 < fifo.getTotalSize()))
237  && (reader.blockSize2 == 0
238  || (reader.startIndex2 >= 0 && reader.startIndex2 < fifo.getTotalSize())))
239  {
240  expect (false, "prepareToRead returned -ve values");
241  break;
242  }
243 
244  bool failed = false;
245 
246  reader.forEach ([&failed, &buffer, &n] (int index)
247  {
248  failed = (buffer[index] != n++) || failed;
249  });
250 
251  if (failed)
252  {
253  expect (false, "read values were incorrect");
254  break;
255  }
256  }
257  }
258 };
259 
260 static AbstractFifoTests fifoUnitTests;
261 
262 #endif
263 
264 } // namespace juce
AbstractFifo(int capacity) noexcept
Creates a FIFO to manage a buffer with the specified capacity.
Class for a scoped reader/writer.
void finishedRead(int numRead) noexcept
Called after reading from the FIFO, to indicate that this many items have now been consumed...
ScopedReadWrite()=default
Construct an unassigned reader/writer.
void combineSeed(int64 seedValue) noexcept
Merges this object&#39;s seed with another value.
Definition: juce_Random.cpp:54
int nextInt() noexcept
Returns the next random 32 bit integer.
Definition: juce_Random.cpp:78
int getTotalSize() const noexcept
Returns the total size of the buffer being managed.
void reset() noexcept
Clears the buffer positions, so that it appears empty.
This is a base class for classes that perform a unit test.
Definition: juce_UnitTest.h:73
void setTotalSize(int newSize) noexcept
Changes the buffer&#39;s total size.
int getNumReady() const noexcept
Returns the number of items that can currently be read from the buffer.
void prepareToWrite(int numToWrite, int &startIndex1, int &blockSize1, int &startIndex2, int &blockSize2) const noexcept
Returns the location within the buffer at which an incoming block of data should be written...
Encapsulates the logic required to implement a lock-free FIFO.
Encapsulates a thread.
Definition: juce_Thread.h:46
ScopedWrite write(int numToWrite) noexcept
Replaces prepareToWrite/finishedWrite with a single function.
void finishedWrite(int numWritten) noexcept
Called after writing from the FIFO, to indicate that this many items have been added.
Type get() const noexcept
Atomically reads and returns the current value.
Definition: juce_Atomic.h:68
void prepareToRead(int numWanted, int &startIndex1, int &blockSize1, int &startIndex2, int &blockSize2) const noexcept
Returns the location within the buffer from which the next block of data should be read...
A random number generator.
Definition: juce_Random.h:38
ScopedRead read(int numToRead) noexcept
Replaces prepareToRead/finishedRead with a single function.
int getFreeSpace() const noexcept
Returns the number of items that can currently be added to the buffer without it overflowing.
~AbstractFifo()
Destructor.