Kaydet (Commit) ffd0e291 authored tarafından Michael Stahl's avatar Michael Stahl

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
üst 493cd526
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <comphelper/guarding.hxx> #include <comphelper/guarding.hxx>
#include <map> #include <map>
#include <limits>
using namespace ::com::sun::star::uno; using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang; using namespace ::com::sun::star::lang;
...@@ -43,46 +44,71 @@ namespace ...@@ -43,46 +44,71 @@ namespace
::cppu::OInterfaceContainerHelper*, ::cppu::OInterfaceContainerHelper*,
::std::less< AccessibleEventNotifier::TClientId > > ClientMap; ::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 struct lclMutex
: public rtl::Static< ::osl::Mutex, lclMutex > {}; : public rtl::Static< ::osl::Mutex, lclMutex > {};
struct Clients struct Clients
: public rtl::Static< ClientMap, 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 void releaseId(AccessibleEventNotifier::TClientId const nId)
static AccessibleEventNotifier::TClientId generateId()
{ {
AccessibleEventNotifier::TClientId nBiggestUsedId = 0; IntervalMap & rFreeIntervals(FreeIntervals::get());
AccessibleEventNotifier::TClientId nFreeId = 0; IntervalMap::iterator const upper(rFreeIntervals.upper_bound(nId));
assert(upper != rFreeIntervals.end());
// look through all registered clients until we find a "gap" in the ids assert(nId < upper->second); // second is start of the interval!
if (nId + 1 == upper->second)
// Note that the following relies on the fact the elements in the map {
// are traveled with ascending keys (aka client ids) --upper->second; // add nId to existing interval
ClientMap &rClients = Clients::get(); }
for ( ClientMap::const_iterator aLookup = rClients.begin(); else
aLookup != rClients.end();
++aLookup
)
{ {
AccessibleEventNotifier::TClientId nCurrent = aLookup->first; IntervalMap::iterator const lower(rFreeIntervals.lower_bound(nId));
OSL_ENSURE( nCurrent > nBiggestUsedId, if (lower != rFreeIntervals.end() && lower->first == nId - 1)
"AccessibleEventNotifier::generateId: " {
"map is expected to be sorted ascending!" ); // add nId by replacing lower with new merged entry
rFreeIntervals.insert(::std::make_pair(nId, lower->second));
if ( nCurrent - nBiggestUsedId > 1 ) rFreeIntervals.erase(lower);
{ // found a "gap" }
nFreeId = nBiggestUsedId + 1; else // otherwise just add new 1-element interval
break; {
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 ) /// generates a new client id
nFreeId = nBiggestUsedId + 1; 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 ), assert(Clients::get().end() == Clients::get().find(nFreeId));
"AccessibleEventNotifier::generateId: algorithm broken!" );
return nFreeId; return nFreeId;
} }
...@@ -158,6 +184,7 @@ namespace comphelper ...@@ -158,6 +184,7 @@ namespace comphelper
// remove it from the clients map // remove it from the clients map
delete aClientPos->second; delete aClientPos->second;
Clients::get().erase( aClientPos ); Clients::get().erase( aClientPos );
releaseId(_nClient);
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
...@@ -183,6 +210,7 @@ namespace comphelper ...@@ -183,6 +210,7 @@ namespace comphelper
// implementations have re-entrance problems and call into // implementations have re-entrance problems and call into
// revokeClient while we are notifying from here) // revokeClient while we are notifying from here)
Clients::get().erase(aClientPos); Clients::get().erase(aClientPos);
releaseId(_nClient);
} }
// notify the "disposing" event for this client // notify the "disposing" event for this client
......
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