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
23namespace juce
24{
25
26AbstractFifo::AbstractFifo (int capacity) noexcept : bufferSize (capacity)
27{
28 jassert (bufferSize > 0);
29}
30
32
33int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
34int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady() - 1; }
35
36int 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
43void AbstractFifo::reset() noexcept
44{
45 validEnd = 0;
46 validStart = 0;
47}
48
49void AbstractFifo::setTotalSize (int newSize) noexcept
50{
51 jassert (newSize > 0);
52 reset();
53 bufferSize = newSize;
54}
55
56//==============================================================================
57void 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
83void 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
95void 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
121void 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//==============================================================================
134template <AbstractFifo::ReadOrWrite mode>
135AbstractFifo::ScopedReadWrite<mode>::ScopedReadWrite (ScopedReadWrite&& other) noexcept
136 : startIndex1 (other.startIndex1),
137 blockSize1 (other.blockSize1),
138 startIndex2 (other.startIndex2),
139 blockSize2 (other.blockSize2)
140{
141 swap (other);
142}
143
144template <AbstractFifo::ReadOrWrite mode>
145AbstractFifo::ScopedReadWrite<mode>&
146AbstractFifo::ScopedReadWrite<mode>::operator= (ScopedReadWrite&& other) noexcept
147{
148 swap (other);
149 return *this;
150}
151
152template <AbstractFifo::ReadOrWrite mode>
153void AbstractFifo::ScopedReadWrite<mode>::swap (ScopedReadWrite& other) noexcept
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
162template class AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>;
163template class AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>;
164
165AbstractFifo::ScopedRead AbstractFifo::read (int numToRead) noexcept { return { *this, numToRead }; }
166AbstractFifo::ScopedWrite AbstractFifo::write (int numToWrite) noexcept { return { *this, numToWrite }; }
167
168
169//==============================================================================
170#if JUCE_UNIT_TESTS
171
172class AbstractFifoTests : public UnitTest
173{
174public:
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
260static AbstractFifoTests fifoUnitTests;
261
262#endif
263
264} // namespace juce
Class for a scoped reader/writer.
ScopedReadWrite()=default
Construct an unassigned reader/writer.
void reset() noexcept
Clears the buffer positions, so that it appears empty.
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.
int getTotalSize() const noexcept
Returns the total size of the buffer being managed.
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.
AbstractFifo(int capacity) noexcept
Creates a FIFO to manage a buffer with the specified capacity.
void finishedRead(int numRead) noexcept
Called after reading from the FIFO, to indicate that this many items have now been consumed.
int getFreeSpace() const noexcept
Returns the number of items that can currently be added to the buffer without it overflowing.
void finishedWrite(int numWritten) noexcept
Called after writing from the FIFO, to indicate that this many items have been added.
int getNumReady() const noexcept
Returns the number of items that can currently be read from the buffer.
void setTotalSize(int newSize) noexcept
Changes the buffer's total size.
This is a base class for classes that perform a unit test.
Type get() const noexcept
Atomically reads and returns the current value.
Definition juce_Atomic.h:68