Browse Source

Removed leak in ValueSource async updater.

tags/2021-05-28
jules 13 years ago
parent
commit
9aab5c7f82
2 changed files with 62 additions and 45 deletions
  1. +60
    -44
      modules/juce_data_structures/values/juce_Value.cpp
  2. +2
    -1
      modules/juce_gui_basics/widgets/juce_TextEditor.cpp

+ 60
- 44
modules/juce_data_structures/values/juce_Value.cpp View File

@@ -27,72 +27,72 @@ class SharedValueSourceUpdater : public ReferenceCountedObject,
private AsyncUpdater private AsyncUpdater
{ {
public: public:
SharedValueSourceUpdater() : insideCallback (false) {}
SharedValueSourceUpdater() : sourcesBeingIterated (nullptr) {}
~SharedValueSourceUpdater() { masterReference.clear(); }
typedef ReferenceCountedObjectPtr<SharedValueSourceUpdater> Ptr;
void update (Value::ValueSource* source)
void update (Value::ValueSource* const source)
{ {
sourcesToUpdate.add (source);
sourcesNeedingAnUpdate.add (source);
if (! insideCallback)
if (sourcesBeingIterated == nullptr)
triggerAsyncUpdate(); triggerAsyncUpdate();
} }
static SharedValueSourceUpdater* getOrCreateSharedUpdater()
void valueDeleted (Value::ValueSource* const source)
{ {
Ptr& p = getSharedUpdater();
if (p == nullptr)
p = new SharedValueSourceUpdater();
sourcesNeedingAnUpdate.removeValue (source);
return p;
if (sourcesBeingIterated != nullptr)
sourcesBeingIterated->removeValue (source);
} }
static void releaseIfUnused()
{
if (Ptr& p = getSharedUpdater())
if (p->getReferenceCount() == 1)
p = nullptr;
}
WeakReference<SharedValueSourceUpdater>::Master masterReference;
private: private:
ReferenceCountedArray<Value::ValueSource> sourcesToUpdate;
bool insideCallback;
static Ptr& getSharedUpdater()
{
static Ptr updater;
return updater;
}
typedef SortedSet<Value::ValueSource*> SourceSet;
SourceSet sourcesNeedingAnUpdate;
SourceSet* sourcesBeingIterated;
void handleAsyncUpdate() void handleAsyncUpdate()
{ {
int maxLoops = 10;
const ScopedValueSetter<bool> inside (insideCallback, true, false);
const Ptr localRef (this);
const ReferenceCountedObjectPtr<SharedValueSourceUpdater> localRef (this);
while (sourcesToUpdate.size() > 0 && --maxLoops >= 0)
{ {
ReferenceCountedArray<Value::ValueSource> sources;
sources.swapWithArray (sourcesToUpdate);
for (int i = 0; i < sources.size(); ++i)
sources.getObjectPointerUnchecked(i)->sendChangeMessage (true);
const ScopedValueSetter<SourceSet*> inside (sourcesBeingIterated, nullptr, nullptr);
int maxLoops = 10;
while (sourcesNeedingAnUpdate.size() > 0)
{
if (--maxLoops == 0)
{
triggerAsyncUpdate();
break;
}
SourceSet sources;
sources.swapWith (sourcesNeedingAnUpdate);
sourcesBeingIterated = &sources;
for (int i = sources.size(); --i >= 0;)
if (i < sources.size())
sources.getUnchecked(i)->sendChangeMessage (true);
}
} }
} }
JUCE_DECLARE_NON_COPYABLE (SharedValueSourceUpdater);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedValueSourceUpdater);
}; };
static WeakReference<SharedValueSourceUpdater> sharedUpdater;
Value::ValueSource::ValueSource() Value::ValueSource::ValueSource()
{ {
} }
Value::ValueSource::~ValueSource() Value::ValueSource::~ValueSource()
{ {
asyncUpdater = nullptr;
SharedValueSourceUpdater::releaseIfUnused();
if (asyncUpdater != nullptr)
static_cast <SharedValueSourceUpdater*> (asyncUpdater.get())->valueDeleted (this);
} }
void Value::ValueSource::sendChangeMessage (const bool synchronous) void Value::ValueSource::sendChangeMessage (const bool synchronous)
@@ -103,17 +103,30 @@ void Value::ValueSource::sendChangeMessage (const bool synchronous)
{ {
if (synchronous) if (synchronous)
{ {
asyncUpdater = nullptr;
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])
v->callListeners(); v->callListeners();
} }
else if (asyncUpdater == nullptr)
else
{ {
SharedValueSourceUpdater* const updater = SharedValueSourceUpdater::getOrCreateSharedUpdater();
asyncUpdater = updater;
SharedValueSourceUpdater* updater = static_cast <SharedValueSourceUpdater*> (asyncUpdater.get());
if (updater == nullptr)
{
if (sharedUpdater == nullptr)
{
asyncUpdater = updater = new SharedValueSourceUpdater();
sharedUpdater = updater;
}
else
{
asyncUpdater = updater = sharedUpdater.get();
}
}
updater->update (this); updater->update (this);
} }
} }
@@ -279,8 +292,11 @@ void Value::removeListener (ValueListener* const listener)
void Value::callListeners() void Value::callListeners()
{ {
Value v (*this); // (create a copy in case this gets deleted by a callback)
listeners.call (&ValueListener::valueChanged, v);
if (listeners.size() > 0)
{
Value v (*this); // (create a copy in case this gets deleted by a callback)
listeners.call (&ValueListener::valueChanged, v);
}
} }
OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const Value& value) OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const Value& value)


+ 2
- 1
modules/juce_gui_basics/widgets/juce_TextEditor.cpp View File

@@ -822,7 +822,7 @@ private:
//============================================================================== //==============================================================================
class TextEditor::TextHolderComponent : public Component, class TextEditor::TextHolderComponent : public Component,
public Timer, public Timer,
private ValueListener
public ValueListener
{ {
public: public:
TextHolderComponent (TextEditor& ed) : owner (ed) TextHolderComponent (TextEditor& ed) : owner (ed)
@@ -962,6 +962,7 @@ TextEditor::~TextEditor()
if (ComponentPeer* const peer = getPeer()) if (ComponentPeer* const peer = getPeer())
peer->dismissPendingTextInput(); peer->dismissPendingTextInput();
textValue.removeListener (textHolder);
textValue.referTo (Value()); textValue.referTo (Value());
clearInternal (0); clearInternal (0);
viewport = nullptr; viewport = nullptr;


Loading…
Cancel
Save