|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2020 - Raw Material Software Limited
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- The code included in this file is provided under the terms of the ISC license
- http://www.isc.org/downloads/software-support-policy/isc-license. Permission
- To use, copy, modify, and/or distribute this software for any purpose with or
- without fee is hereby granted provided that the above copyright notice and
- this permission notice appear in all copies.
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
-
- AbstractFifo::AbstractFifo (int capacity) noexcept : bufferSize (capacity)
- {
- jassert (bufferSize > 0);
- }
-
- AbstractFifo::~AbstractFifo() {}
-
- int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
- int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady() - 1; }
-
- int AbstractFifo::getNumReady() const noexcept
- {
- auto vs = validStart.get();
- auto ve = validEnd.get();
- return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
- }
-
- void AbstractFifo::reset() noexcept
- {
- validEnd = 0;
- validStart = 0;
- }
-
- void AbstractFifo::setTotalSize (int newSize) noexcept
- {
- jassert (newSize > 0);
- reset();
- bufferSize = newSize;
- }
-
- //==============================================================================
- void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1,
- int& startIndex2, int& blockSize2) const noexcept
- {
- auto vs = validStart.get();
- auto ve = validEnd.get();
-
- auto freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve);
- numToWrite = jmin (numToWrite, freeSpace - 1);
-
- if (numToWrite <= 0)
- {
- startIndex1 = 0;
- startIndex2 = 0;
- blockSize1 = 0;
- blockSize2 = 0;
- }
- else
- {
- startIndex1 = ve;
- startIndex2 = 0;
- blockSize1 = jmin (bufferSize - ve, numToWrite);
- numToWrite -= blockSize1;
- blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, vs);
- }
- }
-
- void AbstractFifo::finishedWrite (int numWritten) noexcept
- {
- jassert (numWritten >= 0 && numWritten < bufferSize);
-
- auto newEnd = validEnd.get() + numWritten;
-
- if (newEnd >= bufferSize)
- newEnd -= bufferSize;
-
- validEnd = newEnd;
- }
-
- void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1,
- int& startIndex2, int& blockSize2) const noexcept
- {
- auto vs = validStart.get();
- auto ve = validEnd.get();
-
- auto numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
- numWanted = jmin (numWanted, numReady);
-
- if (numWanted <= 0)
- {
- startIndex1 = 0;
- startIndex2 = 0;
- blockSize1 = 0;
- blockSize2 = 0;
- }
- else
- {
- startIndex1 = vs;
- startIndex2 = 0;
- blockSize1 = jmin (bufferSize - vs, numWanted);
- numWanted -= blockSize1;
- blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, ve);
- }
- }
-
- void AbstractFifo::finishedRead (int numRead) noexcept
- {
- jassert (numRead >= 0 && numRead <= bufferSize);
-
- auto newStart = validStart.get() + numRead;
-
- if (newStart >= bufferSize)
- newStart -= bufferSize;
-
- validStart = newStart;
- }
-
- //==============================================================================
- 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>
- 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 class AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>;
- template class AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>;
-
- AbstractFifo::ScopedRead AbstractFifo::read (int numToRead) noexcept { return { *this, numToRead }; }
- AbstractFifo::ScopedWrite AbstractFifo::write (int numToWrite) noexcept { return { *this, numToWrite }; }
-
-
- //==============================================================================
- //==============================================================================
- #if JUCE_UNIT_TESTS
-
- class AbstractFifoTests : public UnitTest
- {
- public:
- AbstractFifoTests()
- : UnitTest ("Abstract Fifo", UnitTestCategories::containers)
- {}
-
- struct WriteThread : public Thread
- {
- WriteThread (AbstractFifo& f, int* b, Random rng)
- : Thread ("fifo writer"), fifo (f), buffer (b), random (rng)
- {
- startThread();
- }
-
- ~WriteThread()
- {
- stopThread (5000);
- }
-
- void run()
- {
- int n = 0;
-
- while (! threadShouldExit())
- {
- int num = random.nextInt (2000) + 1;
-
- auto writer = fifo.write (num);
-
- 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()));
-
- writer.forEach ([this, &n] (int index) { this->buffer[index] = n++; });
- }
- }
-
- AbstractFifo& fifo;
- int* buffer;
- Random random;
- };
-
- JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6262)
-
- void runTest() override
- {
- beginTest ("AbstractFifo");
-
- int buffer[5000];
- AbstractFifo fifo (numElementsInArray (buffer));
-
- WriteThread writer (fifo, buffer, getRandom());
-
- int n = 0;
- Random r = getRandom();
- r.combineSeed (12345);
-
- for (int count = 100000; --count >= 0;)
- {
- int num = r.nextInt (6000) + 1;
-
- auto reader = fifo.read (num);
-
- 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;
- }
-
- bool failed = false;
-
- reader.forEach ([&failed, &buffer, &n] (int index)
- {
- failed = (buffer[index] != n++) || failed;
- });
-
- if (failed)
- {
- expect (false, "read values were incorrect");
- break;
- }
- }
- }
-
- JUCE_END_IGNORE_WARNINGS_MSVC
- };
-
- static AbstractFifoTests fifoUnitTests;
-
- #endif
-
- } // namespace juce
|