diff options
author | Michael Stahl <mstahl@redhat.com> | 2013-10-21 18:54:42 +0200 |
---|---|---|
committer | Michael Stahl <mstahl@redhat.com> | 2013-10-21 20:05:45 +0200 |
commit | ffd0e2911023e684ca1e206d18b45ef5aa6179f9 (patch) | |
tree | 2b6b572cd50f6e072727b8c5c354070ec01d5ba4 /comphelper | |
parent | 493cd5268bb634ff717d8117e33ea7565321667e (diff) |
fdo#70465: speed up AccessibleEventNotifier::generateId()
Iterating over all entries of a std::map is rather slow, so add a
interval map to manage the free entries.
A first attempt to use boost::icl::interval_set for this was abandoned;
while the releaseId() function would be just 1 line, GCC 4.8.2 at least
is unhappy about boost icl headers for non-obvious reasons:
UnpackedTarball/boost/boost/icl/discrete_interval.hpp:45:225: error:
default argument for template parameter for class enclosing ‘void
boost::icl::boost_concept_check_dummy45(boost_concept_check45*)’
Change-Id: I7b767aefee57df7743dc13a694b6a61abdd536c7
Diffstat (limited to 'comphelper')
-rw-r--r-- | comphelper/source/misc/accessibleeventnotifier.cxx | 86 |
1 files changed, 57 insertions, 29 deletions
diff --git a/comphelper/source/misc/accessibleeventnotifier.cxx b/comphelper/source/misc/accessibleeventnotifier.cxx index b938aa55f3af..c46d54a33420 100644 --- a/comphelper/source/misc/accessibleeventnotifier.cxx +++ b/comphelper/source/misc/accessibleeventnotifier.cxx @@ -24,6 +24,7 @@ #include <comphelper/guarding.hxx> #include <map> +#include <limits> using namespace ::com::sun::star::uno; using namespace ::com::sun::star::lang; @@ -43,46 +44,71 @@ namespace ::cppu::OInterfaceContainerHelper*, ::std::less< AccessibleEventNotifier::TClientId > > ClientMap; + /// key is the end of the interval, value is the start of the interval + typedef ::std::map<AccessibleEventNotifier::TClientId, + AccessibleEventNotifier::TClientId> IntervalMap; + struct lclMutex : public rtl::Static< ::osl::Mutex, lclMutex > {}; struct Clients : public rtl::Static< ClientMap, Clients > {}; + struct FreeIntervals + : public rtl::StaticWithInit<IntervalMap, FreeIntervals> { + IntervalMap operator() () { + IntervalMap map; + map.insert(::std::make_pair( + ::std::numeric_limits<AccessibleEventNotifier::TClientId>::max(), 1)); + return map; + } + }; - /// generates a new client id - static AccessibleEventNotifier::TClientId generateId() + static void releaseId(AccessibleEventNotifier::TClientId const nId) { - AccessibleEventNotifier::TClientId nBiggestUsedId = 0; - AccessibleEventNotifier::TClientId nFreeId = 0; - - // look through all registered clients until we find a "gap" in the ids - - // Note that the following relies on the fact the elements in the map - // are traveled with ascending keys (aka client ids) - ClientMap &rClients = Clients::get(); - for ( ClientMap::const_iterator aLookup = rClients.begin(); - aLookup != rClients.end(); - ++aLookup - ) + IntervalMap & rFreeIntervals(FreeIntervals::get()); + IntervalMap::iterator const upper(rFreeIntervals.upper_bound(nId)); + assert(upper != rFreeIntervals.end()); + assert(nId < upper->second); // second is start of the interval! + if (nId + 1 == upper->second) + { + --upper->second; // add nId to existing interval + } + else { - AccessibleEventNotifier::TClientId nCurrent = aLookup->first; - OSL_ENSURE( nCurrent > nBiggestUsedId, - "AccessibleEventNotifier::generateId: " - "map is expected to be sorted ascending!" ); - - if ( nCurrent - nBiggestUsedId > 1 ) - { // found a "gap" - nFreeId = nBiggestUsedId + 1; - break; + IntervalMap::iterator const lower(rFreeIntervals.lower_bound(nId)); + if (lower != rFreeIntervals.end() && lower->first == nId - 1) + { + // add nId by replacing lower with new merged entry + rFreeIntervals.insert(::std::make_pair(nId, lower->second)); + rFreeIntervals.erase(lower); + } + else // otherwise just add new 1-element interval + { + rFreeIntervals.insert(::std::make_pair(nId, nId)); } - - nBiggestUsedId = nCurrent; } + // currently it's not checked whether intervals can be merged now + // hopefully that won't be a problem in practice + } - if ( !nFreeId ) - nFreeId = nBiggestUsedId + 1; + /// generates a new client id + static AccessibleEventNotifier::TClientId generateId() + { + IntervalMap & rFreeIntervals(FreeIntervals::get()); + assert(!rFreeIntervals.empty()); + IntervalMap::iterator const iter(rFreeIntervals.begin()); + AccessibleEventNotifier::TClientId const nFirst = iter->first; + AccessibleEventNotifier::TClientId const nFreeId = iter->second; + assert(nFreeId <= nFirst); + if (nFreeId != nFirst) + { + ++iter->second; // remove nFreeId from interval + } + else + { + rFreeIntervals.erase(iter); // remove 1-element interval + } - OSL_ENSURE( rClients.end() == rClients.find( nFreeId ), - "AccessibleEventNotifier::generateId: algorithm broken!" ); + assert(Clients::get().end() == Clients::get().find(nFreeId)); return nFreeId; } @@ -158,6 +184,7 @@ namespace comphelper // remove it from the clients map delete aClientPos->second; Clients::get().erase( aClientPos ); + releaseId(_nClient); } //--------------------------------------------------------------------- @@ -183,6 +210,7 @@ namespace comphelper // implementations have re-entrance problems and call into // revokeClient while we are notifying from here) Clients::get().erase(aClientPos); + releaseId(_nClient); } // notify the "disposing" event for this client |