Browse Source

Added methods AbstractFifo::read() and AbstractFifo::write() which return a scope-based object to make it easy to hold, release and iterate blocks of items.

tags/2021-05-28
jules 7 years ago
parent
commit
e2688eec0a
2 changed files with 202 additions and 41 deletions
  1. +100
    -40
      modules/juce_core/containers/juce_AbstractFifo.cpp
  2. +102
    -1
      modules/juce_core/containers/juce_AbstractFifo.h

+ 100
- 40
modules/juce_core/containers/juce_AbstractFifo.cpp View File

@@ -23,8 +23,7 @@
namespace juce
{
AbstractFifo::AbstractFifo (const int capacity) noexcept
: bufferSize (capacity)
AbstractFifo::AbstractFifo (int capacity) noexcept : bufferSize (capacity)
{
jassert (bufferSize > 0);
}
@@ -36,8 +35,8 @@ int AbstractFifo::getFreeSpace() const noexcept { return bufferSize -
int AbstractFifo::getNumReady() const noexcept
{
const int vs = validStart.get();
const int ve = validEnd.get();
auto vs = validStart.get();
auto ve = validEnd.get();
return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
}
@@ -57,10 +56,10 @@ void AbstractFifo::setTotalSize (int newSize) noexcept
//==============================================================================
void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
{
const int vs = validStart.get();
const int ve = validEnd.get();
auto vs = validStart.get();
auto ve = validEnd.get();
const int freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve);
auto freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve);
numToWrite = jmin (numToWrite, freeSpace - 1);
if (numToWrite <= 0)
@@ -84,7 +83,7 @@ void AbstractFifo::finishedWrite (int numWritten) noexcept
{
jassert (numWritten >= 0 && numWritten < bufferSize);
int newEnd = validEnd.get() + numWritten;
auto newEnd = validEnd.get() + numWritten;
if (newEnd >= bufferSize)
newEnd -= bufferSize;
@@ -94,10 +93,10 @@ void AbstractFifo::finishedWrite (int numWritten) noexcept
void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
{
const int vs = validStart.get();
const int ve = validEnd.get();
auto vs = validStart.get();
auto ve = validEnd.get();
const int numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
auto numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
numWanted = jmin (numWanted, numReady);
if (numWanted <= 0)
@@ -121,7 +120,7 @@ void AbstractFifo::finishedRead (int numRead) noexcept
{
jassert (numRead >= 0 && numRead <= bufferSize);
int newStart = validStart.get() + numRead;
auto newStart = validStart.get() + numRead;
if (newStart >= bufferSize)
newStart -= bufferSize;
@@ -129,6 +128,76 @@ void AbstractFifo::finishedRead (int numRead) noexcept
validStart = newStart;
}
//==============================================================================
template <AbstractFifo::ReadOrWrite mode>
AbstractFifo::ScopedReadWrite<mode>::ScopedReadWrite (AbstractFifo& f, int num) noexcept
: fifo (&f)
{
prepare (*fifo, num);
}
template <AbstractFifo::ReadOrWrite mode>
AbstractFifo::ScopedReadWrite<mode>::ScopedReadWrite (ScopedReadWrite&& other) noexcept
: startIndex1 (other.startIndex1),
blockSize1 (other.blockSize1),
startIndex2 (other.startIndex2),
blockSize2 (other.blockSize2)
{
swap (other);
}
template <AbstractFifo::ReadOrWrite mode>
AbstractFifo::ScopedReadWrite<mode>&
AbstractFifo::ScopedReadWrite<mode>::operator= (ScopedReadWrite&& other) noexcept
{
swap (other);
return *this;
}
template <AbstractFifo::ReadOrWrite mode>
AbstractFifo::ScopedReadWrite<mode>::~ScopedReadWrite() noexcept
{
if (fifo != nullptr)
finish (*fifo, blockSize1 + blockSize2);
}
template <AbstractFifo::ReadOrWrite mode>
void AbstractFifo::ScopedReadWrite<mode>::swap (ScopedReadWrite& other) noexcept
{
std::swap (other.fifo, fifo);
std::swap (other.startIndex1, startIndex1);
std::swap (other.blockSize1, blockSize1);
std::swap (other.startIndex2, startIndex2);
std::swap (other.blockSize2, blockSize2);
}
template<>
void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>::prepare (AbstractFifo& f, int num) noexcept
{
f.prepareToRead (num, startIndex1, blockSize1, startIndex2, blockSize2);
}
template<>
void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>::prepare (AbstractFifo& f, int num) noexcept
{
f.prepareToWrite (num, startIndex1, blockSize1, startIndex2, blockSize2);
}
template<>
void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>::finish (AbstractFifo& f, int num) noexcept
{
f.finishedRead (num);
}
template<>
void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>::finish (AbstractFifo& f, int num) noexcept
{
f.finishedWrite (num);
}
template class AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>;
template class AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>;
//==============================================================================
#if JUCE_UNIT_TESTS
@@ -137,9 +206,8 @@ class AbstractFifoTests : public UnitTest
public:
AbstractFifoTests() : UnitTest ("Abstract Fifo", "Containers") {}
class WriteThread : public Thread
struct WriteThread : public Thread
{
public:
WriteThread (AbstractFifo& f, int* b, Random rng)
: Thread ("fifo writer"), fifo (f), buffer (b), random (rng)
{
@@ -159,24 +227,18 @@ public:
{
int num = random.nextInt (2000) + 1;
int start1, size1, start2, size2;
fifo.prepareToWrite (num, start1, size1, start2, size2);
jassert (size1 >= 0 && size2 >= 0);
jassert (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()));
jassert (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize()));
auto writer = fifo.write (num);
for (int i = 0; i < size1; ++i)
buffer [start1 + i] = n++;
jassert (writer.blockSize1 >= 0 && writer.blockSize2 >= 0);
jassert (writer.blockSize1 == 0
|| (writer.startIndex1 >= 0 && writer.startIndex1 < fifo.getTotalSize()));
jassert (writer.blockSize2 == 0
|| (writer.startIndex2 >= 0 && writer.startIndex2 < fifo.getTotalSize()));
for (int i = 0; i < size2; ++i)
buffer [start2 + i] = n++;
fifo.finishedWrite (size1 + size2);
writer.forEach ([this, &n] (int index) { this->buffer[index] = n++; });
}
}
private:
AbstractFifo& fifo;
int* buffer;
Random random;
@@ -186,7 +248,7 @@ public:
{
beginTest ("AbstractFifo");
int buffer [5000];
int buffer[5000];
AbstractFifo fifo (numElementsInArray (buffer));
WriteThread writer (fifo, buffer, getRandom());
@@ -199,12 +261,13 @@ public:
{
int num = r.nextInt (6000) + 1;
int start1, size1, start2, size2;
fifo.prepareToRead (num, start1, size1, start2, size2);
auto reader = fifo.read (num);
if (! (size1 >= 0 && size2 >= 0)
&& (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()))
&& (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize())))
if (! (reader.blockSize1 >= 0 && reader.blockSize2 >= 0)
&& (reader.blockSize1 == 0
|| (reader.startIndex1 >= 0 && reader.startIndex1 < fifo.getTotalSize()))
&& (reader.blockSize2 == 0
|| (reader.startIndex2 >= 0 && reader.startIndex2 < fifo.getTotalSize())))
{
expect (false, "prepareToRead returned -ve values");
break;
@@ -212,19 +275,16 @@ public:
bool failed = false;
for (int i = 0; i < size1; ++i)
failed = (buffer [start1 + i] != n++) || failed;
for (int i = 0; i < size2; ++i)
failed = (buffer [start2 + i] != n++) || failed;
reader.forEach ([this, &failed, &buffer, &n] (int index)
{
failed = (buffer[index] != n++) || failed;
});
if (failed)
{
expect (false, "read values were incorrect");
break;
}
fifo.finishedRead (size1 + size2);
}
}
};


+ 102
- 1
modules/juce_core/containers/juce_AbstractFifo.h View File

@@ -200,11 +200,112 @@ public:
*/
void finishedRead (int numRead) noexcept;
//==============================================================================
private:
enum class ReadOrWrite
{
read,
write
};
public:
template <ReadOrWrite mode>
class ScopedReadWrite final
{
public:
/** Construct an unassigned reader/writer. Doesn't do anything upon destruction. */
ScopedReadWrite() = default;
/** Construct a reader/writer and immediately call prepareRead/prepareWrite
on the abstractFifo which was passed in.
This object will hold a pointer back to the fifo, so make sure that
the fifo outlives this object.
*/
ScopedReadWrite (AbstractFifo&, int num) noexcept;
ScopedReadWrite (const ScopedReadWrite&) = delete;
ScopedReadWrite (ScopedReadWrite&&) noexcept;
ScopedReadWrite& operator= (const ScopedReadWrite&) = delete;
ScopedReadWrite& operator= (ScopedReadWrite&&) noexcept;
/** Calls finishedRead or finishedWrite if this is a non-null scoped
reader/writer.
*/
~ScopedReadWrite() noexcept;
/** Calls the passed function with each index that was deemed valid
for the current read/write operation.
*/
template <typename FunctionToApply>
void forEach (FunctionToApply&& func) const
{
for (auto i = startIndex1, e = startIndex1 + blockSize1; i != e; ++i) func (i);
for (auto i = startIndex2, e = startIndex2 + blockSize2; i != e; ++i) func (i);
}
int startIndex1, blockSize1, startIndex2, blockSize2;
private:
void prepare (AbstractFifo&, int) noexcept;
static void finish (AbstractFifo&, int) noexcept;
void swap (ScopedReadWrite&) noexcept;
AbstractFifo* fifo = nullptr;
};
using ScopedRead = ScopedReadWrite<ReadOrWrite::read>;
using ScopedWrite = ScopedReadWrite<ReadOrWrite::write>;
/** Replaces prepareToRead/finishedRead with a single function.
This function returns an object which contains the start indices and
block sizes, and also automatically finishes the read operation when
it goes out of scope.
@code
{
auto readHandle = fifo.read (4);
for (auto i = 0; i != readHandle.blockSize1; ++i)
{
// read the item at index readHandle.startIndex1 + i
}
for (auto i = 0; i != readHandle.blockSize2; ++i)
{
// read the item at index readHandle.startIndex2 + i
}
} // readHandle goes out of scope here, finishing the read operation
@endcode
*/
ScopedRead read (int numToRead) noexcept { return { *this, numToRead }; }
/** Replaces prepareToWrite/finishedWrite with a single function.
This function returns an object which contains the start indices and
block sizes, and also automatically finishes the write operation when
it goes out of scope.
@code
{
auto writeHandle = fifo.write (5);
for (auto i = 0; i != writeHandle.blockSize1; ++i)
{
// write the item at index writeHandle.startIndex1 + i
}
for (auto i = 0; i != writeHandle.blockSize2; ++i)
{
// write the item at index writeHandle.startIndex2 + i
}
} // writeHandle goes out of scope here, finishing the write operation
@endcode
*/
ScopedWrite write (int numToWrite) noexcept { return { *this, numToWrite }; }
private:
//==============================================================================
int bufferSize;
Atomic <int> validStart, validEnd;
Atomic<int> validStart, validEnd;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AbstractFifo)
};


Loading…
Cancel
Save