Commit 3418fe80 by Jamie Madill Committed by Commit Bot

Optimize Subject's binding method.

Using FixedVector, we can remove the need for dynamic allocation in most of the use cases. Only when we exceed a certain amount of fixed storage do we need to spill into the heap. Bug: angleproject:2389 Bug: chromium:829906 Change-Id: Ib5f7073b58876bfd2400bd87b743bddcee5e5dc8 Reviewed-on: https://chromium-review.googlesource.com/1002884Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org> Reviewed-by: 's avatarLuc Ferron <lucferron@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 3dd8d291
...@@ -18,6 +18,15 @@ ...@@ -18,6 +18,15 @@
namespace angle namespace angle
{ {
namespace
{
template <typename HaystackT, typename NeedleT>
bool IsInContainer(const HaystackT &haystack, const NeedleT &needle)
{
return std::find(haystack.begin(), haystack.end(), needle) != haystack.end();
}
} // anonymous namespace
// Observer implementation. // Observer implementation.
ObserverInterface::~ObserverInterface() = default; ObserverInterface::~ObserverInterface() = default;
...@@ -33,28 +42,57 @@ Subject::~Subject() ...@@ -33,28 +42,57 @@ Subject::~Subject()
bool Subject::hasObservers() const bool Subject::hasObservers() const
{ {
return !mObservers.empty(); return !mFastObservers.empty();
} }
void Subject::addObserver(ObserverBinding *observer) void Subject::addObserver(ObserverBinding *observer)
{ {
ASSERT(std::find(mObservers.begin(), mObservers.end(), observer) == mObservers.end()); ASSERT(!IsInContainer(mFastObservers, observer) && !IsInContainer(mSlowObservers, observer));
mObservers.push_back(observer);
if (!mFastObservers.full())
{
mFastObservers.push_back(observer);
}
else
{
mSlowObservers.push_back(observer);
}
} }
void Subject::removeObserver(ObserverBinding *observer) void Subject::removeObserver(ObserverBinding *observer)
{ {
auto iter = std::find(mObservers.begin(), mObservers.end(), observer); auto iter = std::find(mFastObservers.begin(), mFastObservers.end(), observer);
ASSERT(iter != mObservers.end()); if (iter != mFastObservers.end())
mObservers.erase(iter); {
size_t index = iter - mFastObservers.begin();
std::swap(mFastObservers[index], mFastObservers[mFastObservers.size() - 1]);
mFastObservers.resize(mFastObservers.size() - 1);
if (!mSlowObservers.empty())
{
mFastObservers.push_back(mSlowObservers.back());
mSlowObservers.pop_back();
ASSERT(mFastObservers.full());
}
}
else
{
auto slowIter = std::find(mSlowObservers.begin(), mSlowObservers.end(), observer);
ASSERT(slowIter != mSlowObservers.end());
mSlowObservers.erase(slowIter);
}
} }
void Subject::onStateChange(const gl::Context *context, SubjectMessage message) const void Subject::onStateChange(const gl::Context *context, SubjectMessage message) const
{ {
if (mObservers.empty()) if (mFastObservers.empty())
return; return;
for (const angle::ObserverBinding *receiver : mObservers) for (const angle::ObserverBinding *receiver : mFastObservers)
{
receiver->onStateChange(context, message);
}
for (const angle::ObserverBinding *receiver : mSlowObservers)
{ {
receiver->onStateChange(context, message); receiver->onStateChange(context, message);
} }
...@@ -62,11 +100,17 @@ void Subject::onStateChange(const gl::Context *context, SubjectMessage message) ...@@ -62,11 +100,17 @@ void Subject::onStateChange(const gl::Context *context, SubjectMessage message)
void Subject::resetObservers() void Subject::resetObservers()
{ {
for (angle::ObserverBinding *observer : mObservers) for (angle::ObserverBinding *observer : mFastObservers)
{
observer->onSubjectReset();
}
mFastObservers.clear();
for (angle::ObserverBinding *observer : mSlowObservers)
{ {
observer->onSubjectReset(); observer->onSubjectReset();
} }
mObservers.clear(); mSlowObservers.clear();
} }
// ObserverBinding implementation. // ObserverBinding implementation.
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#ifndef LIBANGLE_OBSERVER_H_ #ifndef LIBANGLE_OBSERVER_H_
#define LIBANGLE_OBSERVER_H_ #define LIBANGLE_OBSERVER_H_
#include "common/FixedVector.h"
#include "common/angleutils.h" #include "common/angleutils.h"
namespace gl namespace gl
...@@ -61,7 +62,11 @@ class Subject : NonCopyable ...@@ -61,7 +62,11 @@ class Subject : NonCopyable
void addObserver(ObserverBinding *observer); void addObserver(ObserverBinding *observer);
void removeObserver(ObserverBinding *observer); void removeObserver(ObserverBinding *observer);
std::vector<ObserverBinding *> mObservers; // Keep a short list of observers so we can allocate/free them quickly. But since we support
// unlimited bindings, have a spill-over list of that uses dynamic allocation.
static constexpr size_t kMaxFixedObservers = 8;
angle::FixedVector<ObserverBinding *, kMaxFixedObservers> mFastObservers;
std::vector<ObserverBinding *> mSlowObservers;
}; };
// Keeps a binding between a Subject and Observer, with a specific subject index. // Keeps a binding between a Subject and Observer, with a specific subject index.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment