comphelper/source/misc/accessibleeventnotifier.cxx | 153 ++++++++++++++------- include/comphelper/accessibleeventnotifier.hxx | 32 ---- 2 files changed, 107 insertions(+), 78 deletions(-)
New commits: commit ffd0e2911023e684ca1e206d18b45ef5aa6179f9 Author: Michael Stahl <mst...@redhat.com> Date: Mon Oct 21 18:54:42 2013 +0200 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 diff --git a/comphelper/source/misc/accessibleeventnotifier.cxx b/comphelper/source/misc/accessibleeventnotifier.cxx index b938aa5..c46d54a 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 commit 493cd5268bb634ff717d8117e33ea7565321667e Author: Michael Stahl <mst...@redhat.com> Date: Mon Oct 21 15:51:58 2013 +0200 remove pointless EventListeners typedef Change-Id: I9cb8ea746c87b394c4c5993de14f692ea018c558 diff --git a/comphelper/source/misc/accessibleeventnotifier.cxx b/comphelper/source/misc/accessibleeventnotifier.cxx index cafe979..b938aa5 100644 --- a/comphelper/source/misc/accessibleeventnotifier.cxx +++ b/comphelper/source/misc/accessibleeventnotifier.cxx @@ -39,11 +39,10 @@ namespace typedef ::std::pair< AccessibleEventNotifier::TClientId, AccessibleEventObject > ClientEvent; - typedef ::cppu::OInterfaceContainerHelper EventListeners; - typedef ::std::map< AccessibleEventNotifier::TClientId, EventListeners*, + typedef ::std::map< AccessibleEventNotifier::TClientId, + ::cppu::OInterfaceContainerHelper*, ::std::less< AccessibleEventNotifier::TClientId > > ClientMap; - struct lclMutex : public rtl::Static< ::osl::Mutex, lclMutex > {}; struct Clients @@ -132,7 +131,8 @@ namespace comphelper TClientId nNewClientId = generateId( ); // the event listeners for the new client - EventListeners* pNewListeners = new EventListeners( lclMutex::get() ); + ::cppu::OInterfaceContainerHelper *const pNewListeners = + new ::cppu::OInterfaceContainerHelper( lclMutex::get() ); // note that we're using our own mutex here, so the listener containers for all // our clients share this same mutex. // this is a reminiscense to the days where the notifier was asynchronous. Today this is @@ -164,7 +164,7 @@ namespace comphelper void AccessibleEventNotifier::revokeClientNotifyDisposing( const TClientId _nClient, const Reference< XInterface >& _rxEventSource ) SAL_THROW( ( ) ) { - EventListeners * pListeners(0); + ::cppu::OInterfaceContainerHelper* pListeners(0); { // rhbz#1001768 drop the mutex before calling disposeAndClear commit 65fce1128cf99c91c9847d613f11fc9ea2325e08 Author: Michael Stahl <mst...@redhat.com> Date: Mon Oct 21 15:49:20 2013 +0200 AccessibleEventNotifier: remove implementation details from header Change-Id: Ia422df4066e77bbe3a43a380ba978815fe46dc9c diff --git a/comphelper/source/misc/accessibleeventnotifier.cxx b/comphelper/source/misc/accessibleeventnotifier.cxx index 14ac88c7..cafe979 100644 --- a/comphelper/source/misc/accessibleeventnotifier.cxx +++ b/comphelper/source/misc/accessibleeventnotifier.cxx @@ -20,8 +20,11 @@ #include <comphelper/accessibleeventnotifier.hxx> #include <osl/diagnose.h> #include <rtl/instance.hxx> +#include <cppuhelper/interfacecontainer.h> #include <comphelper/guarding.hxx> +#include <map> + using namespace ::com::sun::star::uno; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::accessibility; @@ -33,35 +36,39 @@ using namespace ::comphelper; //--------------------------------------------------------------------- namespace { + typedef ::std::pair< AccessibleEventNotifier::TClientId, + AccessibleEventObject > ClientEvent; + + typedef ::cppu::OInterfaceContainerHelper EventListeners; + typedef ::std::map< AccessibleEventNotifier::TClientId, EventListeners*, + ::std::less< AccessibleEventNotifier::TClientId > > ClientMap; + + struct lclMutex : public rtl::Static< ::osl::Mutex, lclMutex > {}; struct Clients - : public rtl::Static< AccessibleEventNotifier::ClientMap, Clients > {}; -} - -//......................................................................... -namespace comphelper -{ -//......................................................................... + : public rtl::Static< ClientMap, Clients > {}; - //--------------------------------------------------------------------- - AccessibleEventNotifier::TClientId AccessibleEventNotifier::generateId() + /// generates a new client id + static AccessibleEventNotifier::TClientId generateId() { - TClientId nBiggestUsedId = 0; - TClientId nFreeId = 0; + 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) - AccessibleEventNotifier::ClientMap &rClients = Clients::get(); + // 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 ) { - TClientId nCurrent = aLookup->first; - OSL_ENSURE( nCurrent > nBiggestUsedId, "AccessibleEventNotifier::generateId: map is expected to be sorted ascending!" ); + 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" @@ -81,6 +88,41 @@ namespace comphelper return nFreeId; } + /** looks up a client in our client map, asserts if it cannot find it or + no event thread is present + + @precond + to be called with our mutex locked + + @param nClient + the id of the client to loopup + @param rPos + out-parameter for the position of the client in the client map + + @return + <TRUE/> if and only if the client could be found and + <arg>rPos</arg> has been filled with it's position + */ + static sal_Bool implLookupClient( + const AccessibleEventNotifier::TClientId nClient, + ClientMap::iterator& rPos ) + { + // look up this client + ClientMap &rClients = Clients::get(); + rPos = rClients.find( nClient ); + OSL_ENSURE( rClients.end() != rPos, + "AccessibleEventNotifier::implLookupClient: invalid client id " + "(did you register your client?)!" ); + + return ( rClients.end() != rPos ); + } +} + +//......................................................................... +namespace comphelper +{ +//......................................................................... + //--------------------------------------------------------------------- AccessibleEventNotifier::TClientId AccessibleEventNotifier::registerClient( ) { @@ -104,17 +146,6 @@ namespace comphelper } //--------------------------------------------------------------------- - sal_Bool AccessibleEventNotifier::implLookupClient( const TClientId _nClient, ClientMap::iterator& _rPos ) - { - // look up this client - AccessibleEventNotifier::ClientMap &rClients = Clients::get(); - _rPos = rClients.find( _nClient ); - OSL_ENSURE( rClients.end() != _rPos, "AccessibleEventNotifier::implLookupClient: invalid client id (did you register your client?)!" ); - - return ( rClients.end() != _rPos ); - } - - //--------------------------------------------------------------------- void AccessibleEventNotifier::revokeClient( const TClientId _nClient ) { ::osl::MutexGuard aGuard( lclMutex::get() ); diff --git a/include/comphelper/accessibleeventnotifier.hxx b/include/comphelper/accessibleeventnotifier.hxx index f0a745b..19d51aa 100644 --- a/include/comphelper/accessibleeventnotifier.hxx +++ b/include/comphelper/accessibleeventnotifier.hxx @@ -22,13 +22,8 @@ #include <com/sun/star/accessibility/AccessibleEventObject.hpp> #include <com/sun/star/accessibility/XAccessibleEventListener.hpp> -#include <osl/thread.hxx> -#include <osl/conditn.hxx> -#include <cppuhelper/interfacecontainer.h> -#include "comphelper/comphelperdllapi.h" -#include <map> -#include <list> +#include <comphelper/comphelperdllapi.h> //......................................................................... namespace comphelper @@ -44,12 +39,6 @@ namespace comphelper public: typedef sal_uInt32 TClientId; - typedef ::std::pair< TClientId, ::com::sun::star::accessibility::AccessibleEventObject > - ClientEvent; - - typedef ::cppu::OInterfaceContainerHelper EventListeners; - typedef ::std::map< TClientId, EventListeners*, ::std::less< TClientId > > ClientMap; - protected: AccessibleEventNotifier( ); // never implemented ~AccessibleEventNotifier( ); // never implemented @@ -130,25 +119,6 @@ namespace comphelper const ::com::sun::star::accessibility::AccessibleEventObject& _rEvent ) SAL_THROW( ( ) ); - private: - /// generates a new client id - COMPHELPER_DLLPRIVATE static TClientId generateId(); - - /** looks up a client in our client map, asserts if it cannot find it or no event thread is present - - @precond - to be called with our mutex locked - - @param _nClient - the id of the client to loopup - @param _rPos - out-parameter for the position of the client in the client map - - @return - <TRUE/> if and only if the client could be found and <arg>_rPos</arg> has been filled with - it's position - */ - COMPHELPER_DLLPRIVATE static sal_Bool implLookupClient( const TClientId _nClient, ClientMap::iterator& _rPos ); }; //.........................................................................
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits