mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Reworked Value to handle changes on a background thread.
This commit is contained in:
parent
27046fd1a7
commit
1c6515ea66
2 changed files with 47 additions and 56 deletions
|
|
@ -22,59 +22,55 @@
|
||||||
==============================================================================
|
==============================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class SharedValueSourceUpdater : public ReferenceCountedObject,
|
struct SharedValueSourceUpdater : private AsyncUpdater
|
||||||
private AsyncUpdater
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SharedValueSourceUpdater() : sourcesBeingIterated (nullptr) {}
|
SharedValueSourceUpdater() {}
|
||||||
~SharedValueSourceUpdater() { masterReference.clear(); }
|
|
||||||
|
|
||||||
void update (Value::ValueSource* const source)
|
void update (Value::ValueSource* const source)
|
||||||
{
|
{
|
||||||
sourcesNeedingAnUpdate.add (source);
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
sourcesNeedingUpdate.addIfNotAlreadyThere (source);
|
||||||
|
}
|
||||||
|
|
||||||
if (sourcesBeingIterated == nullptr)
|
triggerAsyncUpdate();
|
||||||
triggerAsyncUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueDeleted (Value::ValueSource* const source)
|
void valueDeleted (Value::ValueSource* const source)
|
||||||
{
|
{
|
||||||
sourcesNeedingAnUpdate.removeValue (source);
|
const ScopedLock sl (lock);
|
||||||
|
sourcesNeedingUpdate.removeFirstMatchingValue (source);
|
||||||
if (sourcesBeingIterated != nullptr)
|
|
||||||
sourcesBeingIterated->removeValue (source);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WeakReference<SharedValueSourceUpdater>::Master masterReference;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef SortedSet<Value::ValueSource*> SourceSet;
|
Array<Value::ValueSource*> sourcesNeedingUpdate;
|
||||||
SourceSet sourcesNeedingAnUpdate;
|
CriticalSection lock;
|
||||||
SourceSet* sourcesBeingIterated;
|
|
||||||
|
|
||||||
void handleAsyncUpdate() override
|
void handleAsyncUpdate() override
|
||||||
{
|
{
|
||||||
const ReferenceCountedObjectPtr<SharedValueSourceUpdater> localRef (this);
|
SharedResourcePointer<SharedValueSourceUpdater> localRef;
|
||||||
|
|
||||||
|
int maxCallbacks = sourcesNeedingUpdate.size();
|
||||||
|
|
||||||
|
for (;;)
|
||||||
{
|
{
|
||||||
const ScopedValueSetter<SourceSet*> inside (sourcesBeingIterated, nullptr, nullptr);
|
ReferenceCountedObjectPtr<Value::ValueSource> toUpdate;
|
||||||
int maxLoops = 10;
|
|
||||||
|
|
||||||
while (sourcesNeedingAnUpdate.size() > 0)
|
|
||||||
{
|
{
|
||||||
if (--maxLoops == 0)
|
const ScopedLock sl (lock);
|
||||||
{
|
toUpdate = sourcesNeedingUpdate.remove (0);
|
||||||
triggerAsyncUpdate();
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceSet sources;
|
if (toUpdate == nullptr)
|
||||||
sources.swapWith (sourcesNeedingAnUpdate);
|
break;
|
||||||
sourcesBeingIterated = &sources;
|
|
||||||
|
|
||||||
for (int i = sources.size(); --i >= 0;)
|
toUpdate->sendChangeMessage (true);
|
||||||
if (i < sources.size())
|
|
||||||
sources.getUnchecked(i)->sendChangeMessage (true);
|
if (--maxCallbacks <= 0)
|
||||||
|
{
|
||||||
|
triggerAsyncUpdate();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +78,10 @@ private:
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedValueSourceUpdater)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedValueSourceUpdater)
|
||||||
};
|
};
|
||||||
|
|
||||||
static WeakReference<SharedValueSourceUpdater> sharedUpdater;
|
struct Value::ValueSource::Pimpl
|
||||||
|
{
|
||||||
|
SharedResourcePointer<SharedValueSourceUpdater> updater;
|
||||||
|
};
|
||||||
|
|
||||||
Value::ValueSource::ValueSource()
|
Value::ValueSource::ValueSource()
|
||||||
{
|
{
|
||||||
|
|
@ -90,8 +89,8 @@ Value::ValueSource::ValueSource()
|
||||||
|
|
||||||
Value::ValueSource::~ValueSource()
|
Value::ValueSource::~ValueSource()
|
||||||
{
|
{
|
||||||
if (asyncUpdater != nullptr)
|
if (pimpl != nullptr)
|
||||||
static_cast <SharedValueSourceUpdater*> (asyncUpdater.get())->valueDeleted (this);
|
pimpl->updater->valueDeleted (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::ValueSource::sendChangeMessage (const bool synchronous)
|
void Value::ValueSource::sendChangeMessage (const bool synchronous)
|
||||||
|
|
@ -103,7 +102,6 @@ void Value::ValueSource::sendChangeMessage (const bool synchronous)
|
||||||
if (synchronous)
|
if (synchronous)
|
||||||
{
|
{
|
||||||
const ReferenceCountedObjectPtr<ValueSource> localRef (this);
|
const ReferenceCountedObjectPtr<ValueSource> localRef (this);
|
||||||
asyncUpdater = nullptr;
|
|
||||||
|
|
||||||
for (int i = numListeners; --i >= 0;)
|
for (int i = numListeners; --i >= 0;)
|
||||||
if (Value* const v = valuesWithListeners[i])
|
if (Value* const v = valuesWithListeners[i])
|
||||||
|
|
@ -111,22 +109,10 @@ void Value::ValueSource::sendChangeMessage (const bool synchronous)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SharedValueSourceUpdater* updater = static_cast <SharedValueSourceUpdater*> (asyncUpdater.get());
|
if (pimpl == nullptr)
|
||||||
|
pimpl = new Pimpl();
|
||||||
|
|
||||||
if (updater == nullptr)
|
pimpl->updater->update (this);
|
||||||
{
|
|
||||||
if (sharedUpdater == nullptr)
|
|
||||||
{
|
|
||||||
asyncUpdater = updater = new SharedValueSourceUpdater();
|
|
||||||
sharedUpdater = updater;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
asyncUpdater = updater = sharedUpdater.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updater->update (this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -195,13 +181,13 @@ Value& Value::operator= (const Value& other)
|
||||||
|
|
||||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
Value::Value (Value&& other) noexcept
|
Value::Value (Value&& other) noexcept
|
||||||
: value (static_cast <ReferenceCountedObjectPtr <ValueSource>&&> (other.value))
|
: value (static_cast<ReferenceCountedObjectPtr<ValueSource>&&> (other.value))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& Value::operator= (Value&& other) noexcept
|
Value& Value::operator= (Value&& other) noexcept
|
||||||
{
|
{
|
||||||
value = static_cast <ReferenceCountedObjectPtr <ValueSource>&&> (other.value);
|
value = static_cast<ReferenceCountedObjectPtr<ValueSource>&&> (other.value);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -192,8 +192,13 @@ public:
|
||||||
protected:
|
protected:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
friend class Value;
|
friend class Value;
|
||||||
SortedSet <Value*> valuesWithListeners;
|
SortedSet<Value*> valuesWithListeners;
|
||||||
ReferenceCountedObjectPtr<ReferenceCountedObject> asyncUpdater;
|
|
||||||
|
private:
|
||||||
|
struct Pimpl;
|
||||||
|
friend struct Pimpl;
|
||||||
|
friend struct ContainerDeletePolicy<Pimpl>;
|
||||||
|
ScopedPointer<Pimpl> pimpl;
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueSource)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueSource)
|
||||||
};
|
};
|
||||||
|
|
@ -210,8 +215,8 @@ public:
|
||||||
private:
|
private:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
friend class ValueSource;
|
friend class ValueSource;
|
||||||
ReferenceCountedObjectPtr <ValueSource> value;
|
ReferenceCountedObjectPtr<ValueSource> value;
|
||||||
ListenerList <Listener> listeners;
|
ListenerList<Listener> listeners;
|
||||||
|
|
||||||
void callListeners();
|
void callListeners();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue