Browse Source

Performance improvement for Value change notifications.

tags/2021-05-28
jules 13 years ago
parent
commit
66ecd6bc7c
3 changed files with 92 additions and 60 deletions
  1. +79
    -18
      modules/juce_data_structures/values/juce_Value.cpp
  2. +2
    -4
      modules/juce_data_structures/values/juce_Value.h
  3. +11
    -38
      modules/juce_data_structures/values/juce_ValueTree.cpp

+ 79
- 18
modules/juce_data_structures/values/juce_Value.cpp View File

@@ -23,39 +23,100 @@
==============================================================================
*/
class SharedValueSourceUpdater : public ReferenceCountedObject,
private AsyncUpdater
{
public:
SharedValueSourceUpdater() : insideCallback (false) {}
typedef ReferenceCountedObjectPtr<SharedValueSourceUpdater> Ptr;
void update (Value::ValueSource* source)
{
sourcesToUpdate.add (source);
if (! insideCallback)
triggerAsyncUpdate();
}
static SharedValueSourceUpdater* getOrCreateSharedUpdater()
{
Ptr& p = getSharedUpdater();
if (p == nullptr)
p = new SharedValueSourceUpdater();
return p;
}
static void releaseIfUnused()
{
if (Ptr& p = getSharedUpdater())
if (p->getReferenceCount() == 1)
p = nullptr;
}
private:
ReferenceCountedArray<Value::ValueSource> sourcesToUpdate;
bool insideCallback;
static Ptr& getSharedUpdater()
{
static Ptr updater;
return updater;
}
void handleAsyncUpdate()
{
int maxLoops = 10;
const ScopedValueSetter<bool> inside (insideCallback, true, false);
const Ptr 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);
}
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedValueSourceUpdater);
};
Value::ValueSource::ValueSource()
{
}
Value::ValueSource::~ValueSource()
{
asyncUpdater = nullptr;
SharedValueSourceUpdater::releaseIfUnused();
}
void Value::ValueSource::sendChangeMessage (const bool synchronous)
{
if (synchronous)
{
// (hold a local reference to this object in case it's freed during the callbacks)
const ReferenceCountedObjectPtr<ValueSource> localRef (this);
const int numListeners = valuesWithListeners.size();
for (int i = valuesWithListeners.size(); --i >= 0;)
if (numListeners > 0)
{
if (synchronous)
{
Value* const v = valuesWithListeners[i];
asyncUpdater = nullptr;
const ReferenceCountedObjectPtr<ValueSource> localRef (this);
if (v != nullptr)
v->callListeners();
for (int i = numListeners; --i >= 0;)
if (Value* const v = valuesWithListeners[i])
v->callListeners();
}
else if (asyncUpdater == nullptr)
{
SharedValueSourceUpdater* const updater = SharedValueSourceUpdater::getOrCreateSharedUpdater();
asyncUpdater = updater;
updater->update (this);
}
}
else
{
if (valuesWithListeners.size() > 0)
triggerAsyncUpdate();
}
}
void Value::ValueSource::handleAsyncUpdate()
{
sendChangeMessage (true);
}
//==============================================================================


+ 2
- 4
modules/juce_data_structures/values/juce_Value.h View File

@@ -169,8 +169,7 @@ public:
of a ValueSource object. If you're feeling adventurous, you can create your own custom
ValueSource classes to allow Value objects to represent your own custom data items.
*/
class JUCE_API ValueSource : public SingleThreadedReferenceCountedObject,
private AsyncUpdater
class JUCE_API ValueSource : public SingleThreadedReferenceCountedObject
{
public:
ValueSource();
@@ -196,8 +195,7 @@ public:
//==============================================================================
friend class Value;
SortedSet <Value*> valuesWithListeners;
void handleAsyncUpdate();
ReferenceCountedObjectPtr<ReferenceCountedObject> asyncUpdater;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueSource);
};


+ 11
- 38
modules/juce_data_structures/values/juce_ValueTree.cpp View File

@@ -60,11 +60,8 @@ public:
void sendPropertyChangeMessage (ValueTree& tree, const Identifier& property)
{
for (int i = valueTreesWithListeners.size(); --i >= 0;)
{
ValueTree* const v = valueTreesWithListeners[i];
if (v != nullptr)
if (ValueTree* const v = valueTreesWithListeners[i])
v->listeners.call (&ValueTree::Listener::valueTreePropertyChanged, tree, property);
}
}
void sendPropertyChangeMessage (const Identifier& property)
@@ -78,11 +75,8 @@ public:
void sendChildAddedMessage (ValueTree& tree, ValueTree& child)
{
for (int i = valueTreesWithListeners.size(); --i >= 0;)
{
ValueTree* const v = valueTreesWithListeners[i];
if (v != nullptr)
if (ValueTree* const v = valueTreesWithListeners[i])
v->listeners.call (&ValueTree::Listener::valueTreeChildAdded, tree, child);
}
}
void sendChildAddedMessage (ValueTree child)
@@ -96,11 +90,8 @@ public:
void sendChildRemovedMessage (ValueTree& tree, ValueTree& child)
{
for (int i = valueTreesWithListeners.size(); --i >= 0;)
{
ValueTree* const v = valueTreesWithListeners[i];
if (v != nullptr)
if (ValueTree* const v = valueTreesWithListeners[i])
v->listeners.call (&ValueTree::Listener::valueTreeChildRemoved, tree, child);
}
}
void sendChildRemovedMessage (ValueTree child)
@@ -114,11 +105,8 @@ public:
void sendChildOrderChangedMessage (ValueTree& tree)
{
for (int i = valueTreesWithListeners.size(); --i >= 0;)
{
ValueTree* const v = valueTreesWithListeners[i];
if (v != nullptr)
if (ValueTree* const v = valueTreesWithListeners[i])
v->listeners.call (&ValueTree::Listener::valueTreeChildOrderChanged, tree);
}
}
void sendChildOrderChangedMessage()
@@ -134,18 +122,12 @@ public:
ValueTree tree (this);
for (int j = children.size(); --j >= 0;)
{
SharedObject* const child = children.getObjectPointer (j);
if (child != nullptr)
if (SharedObject* const child = children.getObjectPointer (j))
child->sendParentChangeMessage();
}
for (int i = valueTreesWithListeners.size(); --i >= 0;)
{
ValueTree* const v = valueTreesWithListeners[i];
if (v != nullptr)
if (ValueTree* const v = valueTreesWithListeners[i])
v->listeners.call (&ValueTree::Listener::valueTreeParentChanged, tree);
}
}
const var& getProperty (const Identifier& name) const noexcept
@@ -167,9 +149,7 @@ public:
}
else
{
const var* const existingValue = properties.getVarPointer (name);
if (existingValue != nullptr)
if (const var* const existingValue = properties.getVarPointer (name))
{
if (*existingValue != newValue)
undoManager->perform (new SetPropertyAction (this, name, newValue, *existingValue, false, false));
@@ -270,16 +250,10 @@ public:
bool isAChildOf (const SharedObject* const possibleParent) const noexcept
{
const SharedObject* p = parent;
while (p != nullptr)
{
for (const SharedObject* p = parent; p != nullptr; p = p->parent)
if (p == possibleParent)
return true;
p = p->parent;
}
return false;
}
@@ -611,10 +585,9 @@ public:
UndoableAction* createCoalescedAction (UndoableAction* nextAction)
{
MoveChildAction* next = dynamic_cast <MoveChildAction*> (nextAction);
if (next != nullptr && next->parent == parent && next->startIndex == endIndex)
return new MoveChildAction (parent, startIndex, next->endIndex);
if (MoveChildAction* next = dynamic_cast <MoveChildAction*> (nextAction))
if (next->parent == parent && next->startIndex == endIndex)
return new MoveChildAction (parent, startIndex, next->endIndex);
return nullptr;
}


Loading…
Cancel
Save