summaryrefslogtreecommitdiff
path: root/comphelper/source/misc/accessibleeventnotifier.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'comphelper/source/misc/accessibleeventnotifier.cxx')
-rw-r--r--comphelper/source/misc/accessibleeventnotifier.cxx86
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