diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 355c5cd6e1..30139fd987 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -2341,7 +2341,13 @@ AbstractFifo::~AbstractFifo() {} int AbstractFifo::getTotalSize() const throw() { return bufferSize; } int AbstractFifo::getFreeSpace() const throw() { return bufferSize - getNumReady(); } -int AbstractFifo::getNumReady() const throw() { return validEnd.get() - validStart.get(); } + +int AbstractFifo::getNumReady() const throw() +{ + const int vs = validStart.get(); + const int ve = validEnd.get(); + return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve)); +} void AbstractFifo::reset() throw() { @@ -2359,10 +2365,10 @@ void AbstractFifo::setTotalSize (int newSize) throw() void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const throw() { const int vs = validStart.get(); - const int ve = validEnd.get(); + const int ve = validEnd.value; - const int freeSpace = bufferSize - (ve - vs); - numToWrite = jmin (numToWrite, freeSpace); + const int freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve); + numToWrite = jmin (numToWrite, freeSpace - 1); if (numToWrite <= 0) { @@ -2373,26 +2379,30 @@ void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockS } else { - startIndex1 = (int) (ve % bufferSize); + startIndex1 = ve; startIndex2 = 0; - blockSize1 = jmin (bufferSize - startIndex1, numToWrite); + blockSize1 = jmin (bufferSize - ve, numToWrite); numToWrite -= blockSize1; - blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, (int) (vs % bufferSize)); + blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, vs); } } void AbstractFifo::finishedWrite (int numWritten) throw() { jassert (numWritten >= 0 && numWritten < bufferSize); - validEnd += numWritten; + int newEnd = validEnd.value + numWritten; + if (newEnd >= bufferSize) + newEnd -= bufferSize; + + validEnd = newEnd; } void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const throw() { - const int vs = validStart.get(); + const int vs = validStart.value; const int ve = validEnd.get(); - const int numReady = ve - vs; + const int numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve)); numWanted = jmin (numWanted, numReady); if (numWanted <= 0) @@ -2404,20 +2414,127 @@ void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSiz } else { - startIndex1 = (int) (vs % bufferSize); + startIndex1 = vs; startIndex2 = 0; - blockSize1 = jmin (bufferSize - startIndex1, numWanted); + blockSize1 = jmin (bufferSize - vs, numWanted); numWanted -= blockSize1; - blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, (int) (ve % bufferSize)); + blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, ve); } } void AbstractFifo::finishedRead (int numRead) throw() { - jassert (numRead >= 0 && numRead < bufferSize); - validStart += numRead; + jassert (numRead >= 0 && numRead <= bufferSize); + + int newStart = validStart.value + numRead; + if (newStart >= bufferSize) + newStart -= bufferSize; + + validStart = newStart; } +#if JUCE_UNIT_TESTS + +class AbstractFifoTests : public UnitTest +{ +public: + AbstractFifoTests() : UnitTest ("Abstract Fifo") {} + + class WriteThread : public Thread + { + public: + WriteThread (AbstractFifo& fifo_, int* buffer_) + : Thread ("fifo writer"), fifo (fifo_), buffer (buffer_) + { + startThread(); + } + + ~WriteThread() + { + stopThread (5000); + } + + void run() + { + int n = 0; + + while (! threadShouldExit()) + { + int num = Random::getSystemRandom().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())); + + int i; + for (i = 0; i < size1; ++i) + buffer [start1 + i] = n++; + + for (i = 0; i < size2; ++i) + buffer [start2 + i] = n++; + + fifo.finishedWrite (size1 + size2); + } + } + + private: + AbstractFifo& fifo; + int* buffer; + }; + + void runTest() + { + beginTest ("AbstractFifo"); + + int buffer [5000]; + AbstractFifo fifo (numElementsInArray (buffer)); + + WriteThread writer (fifo, buffer); + + int n = 0; + + for (int count = 1000000; --count >= 0;) + { + int num = Random::getSystemRandom().nextInt (6000) + 1; + + int start1, size1, start2, size2; + fifo.prepareToRead (num, start1, size1, start2, size2); + + if (! (size1 >= 0 && size2 >= 0) + && (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize())) + && (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize()))) + { + expect (false, "prepareToRead returned -ve values"); + break; + } + + bool failed = false; + + int i; + for (i = 0; i < size1; ++i) + failed = (buffer [start1 + i] != n++) || failed; + + for (i = 0; i < size2; ++i) + failed = (buffer [start2 + i] != n++) || failed; + + if (failed) + { + expect (false, "read values were incorrect"); + break; + } + + fifo.finishedRead (size1 + size2); + } + } +}; + +static AbstractFifoTests fifoUnitTests; + +#endif + END_JUCE_NAMESPACE /*** End of inlined file: juce_AbstractFifo.cpp ***/ @@ -4948,7 +5065,12 @@ public: visitor.useSymbol (Symbol (scope.getScopeUID(), getSymbol()->symbol)); SymbolVisitingVisitor v (right, visitor, recursionDepth + 1); - scope.visitRelativeScope (getSymbol()->symbol, v); + + try + { + scope.visitRelativeScope (getSymbol()->symbol, v); + } + catch (...) {} } void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth) @@ -4957,7 +5079,12 @@ public: getSymbol()->renameSymbol (oldSymbol, newName, scope, recursionDepth); SymbolRenamingVisitor visitor (right, oldSymbol, newName, recursionDepth + 1); - scope.visitRelativeScope (getSymbol()->symbol, visitor); + + try + { + scope.visitRelativeScope (getSymbol()->symbol, visitor); + } + catch (...) {} } private: @@ -5792,8 +5919,9 @@ double Expression::Scope::evaluateFunction (const String& functionName, const do throw Helpers::EvaluationError ("Unknown function: \"" + functionName + "\""); } -void Expression::Scope::visitRelativeScope (const String&, Visitor&) const +void Expression::Scope::visitRelativeScope (const String& scopeName, Visitor&) const { + throw Helpers::EvaluationError ("Unknown symbol: " + scopeName); } const String Expression::Scope::getScopeUID() const @@ -61611,7 +61739,7 @@ namespace ComponentBuilderHelpers const ValueTree& state, Component* parent) { Component* const c = type.addNewComponentFromState (state, parent); - jassert (c != 0); + jassert (c != 0 && c->getParentComponent() == parent); c->setComponentID (getStateId (state)); return c; } @@ -80376,6 +80504,8 @@ void RelativeCoordinatePositionerBase::ComponentScope::visitRelativeScope (const if (targetComp != 0) visitor.visit (ComponentScope (*targetComp)); + else + Expression::Scope::visitRelativeScope (scopeName, visitor); } const String RelativeCoordinatePositionerBase::ComponentScope::getScopeUID() const @@ -80479,6 +80609,10 @@ public: else { // The named component doesn't exist, so we'll watch the parent for changes in case it appears later.. + Component* const parent = component.getParentComponent(); + if (parent != 0) + positioner.registerComponentListener (*parent); + positioner.registerComponentListener (component); ok = false; } @@ -80511,10 +80645,17 @@ void RelativeCoordinatePositionerBase::componentParentHierarchyChanged (Componen apply(); } +void RelativeCoordinatePositionerBase::componentChildrenChanged (Component& changed) +{ + if (getComponent().getParentComponent() == &changed && ! registeredOk) + apply(); +} + void RelativeCoordinatePositionerBase::componentBeingDeleted (Component& component) { jassert (sourceComponents.contains (&component)); sourceComponents.removeValue (&component); + registeredOk = false; } void RelativeCoordinatePositionerBase::markersChanged (MarkerList*) diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 5576dd18ad..44c0e0f2b5 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -45966,6 +45966,7 @@ public: void componentMovedOrResized (Component&, bool, bool); void componentParentHierarchyChanged (Component&); + void componentChildrenChanged (Component& component); void componentBeingDeleted (Component& component); void markersChanged (MarkerList*); void markerListBeingDeleted (MarkerList* markerList); diff --git a/src/containers/juce_AbstractFifo.cpp b/src/containers/juce_AbstractFifo.cpp index 534c87da00..46dde69868 100644 --- a/src/containers/juce_AbstractFifo.cpp +++ b/src/containers/juce_AbstractFifo.cpp @@ -41,7 +41,13 @@ AbstractFifo::~AbstractFifo() {} int AbstractFifo::getTotalSize() const throw() { return bufferSize; } int AbstractFifo::getFreeSpace() const throw() { return bufferSize - getNumReady(); } -int AbstractFifo::getNumReady() const throw() { return validEnd.get() - validStart.get(); } + +int AbstractFifo::getNumReady() const throw() +{ + const int vs = validStart.get(); + const int ve = validEnd.get(); + return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve)); +} void AbstractFifo::reset() throw() { @@ -60,10 +66,10 @@ void AbstractFifo::setTotalSize (int newSize) throw() void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const throw() { const int vs = validStart.get(); - const int ve = validEnd.get(); + const int ve = validEnd.value; - const int freeSpace = bufferSize - (ve - vs); - numToWrite = jmin (numToWrite, freeSpace); + const int freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve); + numToWrite = jmin (numToWrite, freeSpace - 1); if (numToWrite <= 0) { @@ -74,26 +80,30 @@ void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockS } else { - startIndex1 = (int) (ve % bufferSize); + startIndex1 = ve; startIndex2 = 0; - blockSize1 = jmin (bufferSize - startIndex1, numToWrite); + blockSize1 = jmin (bufferSize - ve, numToWrite); numToWrite -= blockSize1; - blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, (int) (vs % bufferSize)); + blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, vs); } } void AbstractFifo::finishedWrite (int numWritten) throw() { jassert (numWritten >= 0 && numWritten < bufferSize); - validEnd += numWritten; + int newEnd = validEnd.value + numWritten; + if (newEnd >= bufferSize) + newEnd -= bufferSize; + + validEnd = newEnd; } void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const throw() { - const int vs = validStart.get(); + const int vs = validStart.value; const int ve = validEnd.get(); - const int numReady = ve - vs; + const int numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve)); numWanted = jmin (numWanted, numReady); if (numWanted <= 0) @@ -105,19 +115,132 @@ void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSiz } else { - startIndex1 = (int) (vs % bufferSize); + startIndex1 = vs; startIndex2 = 0; - blockSize1 = jmin (bufferSize - startIndex1, numWanted); + blockSize1 = jmin (bufferSize - vs, numWanted); numWanted -= blockSize1; - blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, (int) (ve % bufferSize)); + blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, ve); } } void AbstractFifo::finishedRead (int numRead) throw() { - jassert (numRead >= 0 && numRead < bufferSize); - validStart += numRead; + jassert (numRead >= 0 && numRead <= bufferSize); + + int newStart = validStart.value + numRead; + if (newStart >= bufferSize) + newStart -= bufferSize; + + validStart = newStart; } +//============================================================================== +//============================================================================== +#if JUCE_UNIT_TESTS + +#include "../utilities/juce_UnitTest.h" +#include "../maths/juce_Random.h" +#include "../threads/juce_Thread.h" + + +class AbstractFifoTests : public UnitTest +{ +public: + AbstractFifoTests() : UnitTest ("Abstract Fifo") {} + + class WriteThread : public Thread + { + public: + WriteThread (AbstractFifo& fifo_, int* buffer_) + : Thread ("fifo writer"), fifo (fifo_), buffer (buffer_) + { + startThread(); + } + + ~WriteThread() + { + stopThread (5000); + } + + void run() + { + int n = 0; + + while (! threadShouldExit()) + { + int num = Random::getSystemRandom().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())); + + int i; + for (i = 0; i < size1; ++i) + buffer [start1 + i] = n++; + + for (i = 0; i < size2; ++i) + buffer [start2 + i] = n++; + + fifo.finishedWrite (size1 + size2); + } + } + + private: + AbstractFifo& fifo; + int* buffer; + }; + + void runTest() + { + beginTest ("AbstractFifo"); + + int buffer [5000]; + AbstractFifo fifo (numElementsInArray (buffer)); + + WriteThread writer (fifo, buffer); + + int n = 0; + + for (int count = 1000000; --count >= 0;) + { + int num = Random::getSystemRandom().nextInt (6000) + 1; + + int start1, size1, start2, size2; + fifo.prepareToRead (num, start1, size1, start2, size2); + + if (! (size1 >= 0 && size2 >= 0) + && (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize())) + && (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize()))) + { + expect (false, "prepareToRead returned -ve values"); + break; + } + + bool failed = false; + + int i; + for (i = 0; i < size1; ++i) + failed = (buffer [start1 + i] != n++) || failed; + + for (i = 0; i < size2; ++i) + failed = (buffer [start2 + i] != n++) || failed; + + if (failed) + { + expect (false, "read values were incorrect"); + break; + } + + fifo.finishedRead (size1 + size2); + } + } +}; + +static AbstractFifoTests fifoUnitTests; + +#endif END_JUCE_NAMESPACE diff --git a/src/gui/components/layout/juce_ComponentBuilder.cpp b/src/gui/components/layout/juce_ComponentBuilder.cpp index 1c944e9e6d..6dfc19c493 100644 --- a/src/gui/components/layout/juce_ComponentBuilder.cpp +++ b/src/gui/components/layout/juce_ComponentBuilder.cpp @@ -74,7 +74,7 @@ namespace ComponentBuilderHelpers const ValueTree& state, Component* parent) { Component* const c = type.addNewComponentFromState (state, parent); - jassert (c != 0); + jassert (c != 0 && c->getParentComponent() == parent); c->setComponentID (getStateId (state)); return c; } diff --git a/src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp b/src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp index 5f2f8af420..5bf2097dfa 100644 --- a/src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp +++ b/src/gui/components/positioning/juce_RelativeCoordinatePositioner.cpp @@ -71,6 +71,8 @@ void RelativeCoordinatePositionerBase::ComponentScope::visitRelativeScope (const if (targetComp != 0) visitor.visit (ComponentScope (*targetComp)); + else + Expression::Scope::visitRelativeScope (scopeName, visitor); } const String RelativeCoordinatePositionerBase::ComponentScope::getScopeUID() const @@ -175,6 +177,10 @@ public: else { // The named component doesn't exist, so we'll watch the parent for changes in case it appears later.. + Component* const parent = component.getParentComponent(); + if (parent != 0) + positioner.registerComponentListener (*parent); + positioner.registerComponentListener (component); ok = false; } @@ -208,10 +214,17 @@ void RelativeCoordinatePositionerBase::componentParentHierarchyChanged (Componen apply(); } +void RelativeCoordinatePositionerBase::componentChildrenChanged (Component& changed) +{ + if (getComponent().getParentComponent() == &changed && ! registeredOk) + apply(); +} + void RelativeCoordinatePositionerBase::componentBeingDeleted (Component& component) { jassert (sourceComponents.contains (&component)); sourceComponents.removeValue (&component); + registeredOk = false; } void RelativeCoordinatePositionerBase::markersChanged (MarkerList*) diff --git a/src/gui/components/positioning/juce_RelativeCoordinatePositioner.h b/src/gui/components/positioning/juce_RelativeCoordinatePositioner.h index a7bc77f2f1..91fbabcca4 100644 --- a/src/gui/components/positioning/juce_RelativeCoordinatePositioner.h +++ b/src/gui/components/positioning/juce_RelativeCoordinatePositioner.h @@ -45,6 +45,7 @@ public: void componentMovedOrResized (Component&, bool, bool); void componentParentHierarchyChanged (Component&); + void componentChildrenChanged (Component& component); void componentBeingDeleted (Component& component); void markersChanged (MarkerList*); void markerListBeingDeleted (MarkerList* markerList); diff --git a/src/maths/juce_Expression.cpp b/src/maths/juce_Expression.cpp index 738a62596a..a74b71ee25 100644 --- a/src/maths/juce_Expression.cpp +++ b/src/maths/juce_Expression.cpp @@ -337,7 +337,12 @@ public: visitor.useSymbol (Symbol (scope.getScopeUID(), getSymbol()->symbol)); SymbolVisitingVisitor v (right, visitor, recursionDepth + 1); - scope.visitRelativeScope (getSymbol()->symbol, v); + + try + { + scope.visitRelativeScope (getSymbol()->symbol, v); + } + catch (...) {} } void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth) @@ -346,7 +351,12 @@ public: getSymbol()->renameSymbol (oldSymbol, newName, scope, recursionDepth); SymbolRenamingVisitor visitor (right, oldSymbol, newName, recursionDepth + 1); - scope.visitRelativeScope (getSymbol()->symbol, visitor); + + try + { + scope.visitRelativeScope (getSymbol()->symbol, visitor); + } + catch (...) {} } private: @@ -1196,8 +1206,9 @@ double Expression::Scope::evaluateFunction (const String& functionName, const do throw Helpers::EvaluationError ("Unknown function: \"" + functionName + "\""); } -void Expression::Scope::visitRelativeScope (const String&, Visitor&) const +void Expression::Scope::visitRelativeScope (const String& scopeName, Visitor&) const { + throw Helpers::EvaluationError ("Unknown symbol: " + scopeName); } const String Expression::Scope::getScopeUID() const