OpenShot Library | libopenshot-audio 0.2.0
juce_AbstractFifo.h
1
2/** @weakgroup juce_core-containers
3 * @{
4 */
5/*
6 ==============================================================================
7
8 This file is part of the JUCE library.
9 Copyright (c) 2017 - ROLI Ltd.
10
11 JUCE is an open source library subject to commercial or open-source
12 licensing.
13
14 The code included in this file is provided under the terms of the ISC license
15 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
16 To use, copy, modify, and/or distribute this software for any purpose with or
17 without fee is hereby granted provided that the above copyright notice and
18 this permission notice appear in all copies.
19
20 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22 DISCLAIMED.
23
24 ==============================================================================
25*/
26
27namespace juce
28{
29
30//==============================================================================
31/**
32 Encapsulates the logic required to implement a lock-free FIFO.
33
34 This class handles the logic needed when building a single-reader, single-writer FIFO.
35
36 It doesn't actually hold any data itself, but your FIFO class can use one of these to manage
37 its position and status when reading or writing to it.
38
39 To use it, you can call prepareToWrite() to determine the position within your own buffer that
40 an incoming block of data should be stored, and prepareToRead() to find out when the next
41 outgoing block should be read from.
42
43 e.g.
44 @code
45 struct MyFifo
46 {
47 void addToFifo (const int* someData, int numItems)
48 {
49 int start1, size1, start2, size2;
50 abstractFifo.prepareToWrite (numItems, start1, size1, start2, size2);
51
52 if (size1 > 0)
53 copySomeData (myBuffer + start1, someData, size1);
54
55 if (size2 > 0)
56 copySomeData (myBuffer + start2, someData + size1, size2);
57
58 abstractFifo.finishedWrite (size1 + size2);
59 }
60
61 void readFromFifo (int* someData, int numItems)
62 {
63 int start1, size1, start2, size2;
64 abstractFifo.prepareToRead (numItems, start1, size1, start2, size2);
65
66 if (size1 > 0)
67 copySomeData (someData, myBuffer + start1, size1);
68
69 if (size2 > 0)
70 copySomeData (someData + size1, myBuffer + start2, size2);
71
72 abstractFifo.finishedRead (size1 + size2);
73 }
74
75 AbstractFifo abstractFifo { 1024 };
76 int myBuffer[1024];
77 };
78 @endcode
79
80 @tags{Core}
81*/
83{
84public:
85 //==============================================================================
86 /** Creates a FIFO to manage a buffer with the specified capacity. */
87 AbstractFifo (int capacity) noexcept;
88
89 /** Destructor */
91
92 //==============================================================================
93 /** Returns the total size of the buffer being managed. */
94 int getTotalSize() const noexcept;
95
96 /** Returns the number of items that can currently be added to the buffer without it overflowing. */
97 int getFreeSpace() const noexcept;
98
99 /** Returns the number of items that can currently be read from the buffer. */
100 int getNumReady() const noexcept;
101
102 /** Clears the buffer positions, so that it appears empty. */
103 void reset() noexcept;
104
105 /** Changes the buffer's total size.
106 Note that this isn't thread-safe, so don't call it if there's any danger that it
107 might overlap with a call to any other method in this class!
108 */
109 void setTotalSize (int newSize) noexcept;
110
111 //==============================================================================
112 /** Returns the location within the buffer at which an incoming block of data should be written.
113
114 Because the section of data that you want to add to the buffer may overlap the end
115 and wrap around to the start, two blocks within your buffer are returned, and you
116 should copy your data into the first one, with any remaining data spilling over into
117 the second.
118
119 If the number of items you ask for is too large to fit within the buffer's free space, then
120 blockSize1 + blockSize2 may add up to a lower value than numToWrite. If this happens, you
121 may decide to keep waiting and re-trying the method until there's enough space available.
122
123 After calling this method, if you choose to write your data into the blocks returned, you
124 must call finishedWrite() to tell the FIFO how much data you actually added.
125
126 e.g.
127 @code
128 void addToFifo (const int* someData, int numItems)
129 {
130 int start1, size1, start2, size2;
131 prepareToWrite (numItems, start1, size1, start2, size2);
132
133 if (size1 > 0)
134 copySomeData (myBuffer + start1, someData, size1);
135
136 if (size2 > 0)
137 copySomeData (myBuffer + start2, someData + size1, size2);
138
139 finishedWrite (size1 + size2);
140 }
141 @endcode
142
143 @param numToWrite indicates how many items you'd like to add to the buffer
144 @param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
145 @param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
146 @param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
147 the first block should be written
148 @param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
149 @see finishedWrite
150 */
151 void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
152
153 /** Called after writing from the FIFO, to indicate that this many items have been added.
154 @see prepareToWrite
155 */
156 void finishedWrite (int numWritten) noexcept;
157
158 /** Returns the location within the buffer from which the next block of data should be read.
159
160 Because the section of data that you want to read from the buffer may overlap the end
161 and wrap around to the start, two blocks within your buffer are returned, and you
162 should read from both of them.
163
164 If the number of items you ask for is greater than the amount of data available, then
165 blockSize1 + blockSize2 may add up to a lower value than numWanted. If this happens, you
166 may decide to keep waiting and re-trying the method until there's enough data available.
167
168 After calling this method, if you choose to read the data, you must call finishedRead() to
169 tell the FIFO how much data you have consumed.
170
171 e.g.
172 @code
173 void readFromFifo (int* someData, int numItems)
174 {
175 int start1, size1, start2, size2;
176 prepareToRead (numSamples, start1, size1, start2, size2);
177
178 if (size1 > 0)
179 copySomeData (someData, myBuffer + start1, size1);
180
181 if (size2 > 0)
182 copySomeData (someData + size1, myBuffer + start2, size2);
183
184 finishedRead (size1 + size2);
185 }
186 @endcode
187
188 @param numWanted indicates how many items you'd like to add to the buffer
189 @param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
190 @param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
191 @param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
192 the first block should be written
193 @param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
194 @see finishedRead
195 */
196 void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
197
198 /** Called after reading from the FIFO, to indicate that this many items have now been consumed.
199 @see prepareToRead
200 */
201 void finishedRead (int numRead) noexcept;
202
203 //==============================================================================
204
205private:
206 enum class ReadOrWrite
207 {
208 read,
209 write
210 };
211
212public:
213 /** Class for a scoped reader/writer */
214 template <ReadOrWrite mode>
215 class ScopedReadWrite final
216 {
217 public:
218 /** Construct an unassigned reader/writer. Doesn't do anything upon destruction. */
219 ScopedReadWrite() = default;
220
221 /** Construct a reader/writer and immediately call prepareRead/prepareWrite
222 on the abstractFifo which was passed in.
223 This object will hold a pointer back to the fifo, so make sure that
224 the fifo outlives this object.
225 */
226 ScopedReadWrite (AbstractFifo& f, int num) noexcept : fifo (&f)
227 {
228 prepare (*fifo, num);
229 }
230
231 ScopedReadWrite (const ScopedReadWrite&) = delete;
232 ScopedReadWrite (ScopedReadWrite&&) noexcept;
233
234 ScopedReadWrite& operator= (const ScopedReadWrite&) = delete;
235 ScopedReadWrite& operator= (ScopedReadWrite&&) noexcept;
236
237 /** Calls finishedRead or finishedWrite if this is a non-null scoped
238 reader/writer.
239 */
240 ~ScopedReadWrite() noexcept
241 {
242 if (fifo != nullptr)
243 finish (*fifo, blockSize1 + blockSize2);
244 }
245
246 /** Calls the passed function with each index that was deemed valid
247 for the current read/write operation.
248 */
249 template <typename FunctionToApply>
250 void forEach (FunctionToApply&& func) const
251 {
252 for (auto i = startIndex1, e = startIndex1 + blockSize1; i != e; ++i) func (i);
253 for (auto i = startIndex2, e = startIndex2 + blockSize2; i != e; ++i) func (i);
254 }
255
256 int startIndex1, blockSize1, startIndex2, blockSize2;
257
258 private:
259 void prepare (AbstractFifo&, int) noexcept;
260 static void finish (AbstractFifo&, int) noexcept;
261 void swap (ScopedReadWrite&) noexcept;
262
263 AbstractFifo* fifo = nullptr;
264 };
265
266 using ScopedRead = ScopedReadWrite<ReadOrWrite::read>;
267 using ScopedWrite = ScopedReadWrite<ReadOrWrite::write>;
268
269 /** Replaces prepareToRead/finishedRead with a single function.
270 This function returns an object which contains the start indices and
271 block sizes, and also automatically finishes the read operation when
272 it goes out of scope.
273 @code
274 {
275 auto readHandle = fifo.read (4);
276
277 for (auto i = 0; i != readHandle.blockSize1; ++i)
278 {
279 // read the item at index readHandle.startIndex1 + i
280 }
281
282 for (auto i = 0; i != readHandle.blockSize2; ++i)
283 {
284 // read the item at index readHandle.startIndex2 + i
285 }
286 } // readHandle goes out of scope here, finishing the read operation
287 @endcode
288 */
289 ScopedRead read (int numToRead) noexcept;
290
291 /** Replaces prepareToWrite/finishedWrite with a single function.
292 This function returns an object which contains the start indices and
293 block sizes, and also automatically finishes the write operation when
294 it goes out of scope.
295 @code
296 {
297 auto writeHandle = fifo.write (5);
298
299 for (auto i = 0; i != writeHandle.blockSize1; ++i)
300 {
301 // write the item at index writeHandle.startIndex1 + i
302 }
303
304 for (auto i = 0; i != writeHandle.blockSize2; ++i)
305 {
306 // write the item at index writeHandle.startIndex2 + i
307 }
308 } // writeHandle goes out of scope here, finishing the write operation
309 @endcode
310 */
311 ScopedWrite write (int numToWrite) noexcept;
312
313private:
314 //==============================================================================
315 int bufferSize;
316 Atomic<int> validStart, validEnd;
317
318 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AbstractFifo)
319};
320
321template<>
322inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>::finish (AbstractFifo& f, int num) noexcept
323{
324 f.finishedRead (num);
325}
326
327template<>
328inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>::finish (AbstractFifo& f, int num) noexcept
329{
330 f.finishedWrite (num);
331}
332
333template<>
334inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>::prepare (AbstractFifo& f, int num) noexcept
335{
336 f.prepareToRead (num, startIndex1, blockSize1, startIndex2, blockSize2);
337}
338
339template<>
340inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>::prepare (AbstractFifo& f, int num) noexcept
341{
342 f.prepareToWrite (num, startIndex1, blockSize1, startIndex2, blockSize2);
343}
344
345
346} // namespace juce
347
348/** @}*/
Class for a scoped reader/writer.
ScopedReadWrite(AbstractFifo &f, int num) noexcept
Construct a reader/writer and immediately call prepareRead/prepareWrite on the abstractFifo which was...
void forEach(FunctionToApply &&func) const
Calls the passed function with each index that was deemed valid for the current read/write operation.
ScopedReadWrite()=default
Construct an unassigned reader/writer.
Encapsulates the logic required to implement a lock-free FIFO.
#define JUCE_API
This macro is added to all JUCE public class declarations.
A simple wrapper around std::atomic.
Definition juce_Atomic.h:46