[Libreoffice-commits] core.git: include/comphelper sc/source

Noel Grandin (via logerrit) logerrit at kemper.freedesktop.org
Tue Aug 20 18:35:58 UTC 2019


 include/comphelper/interfacecontainer3.hxx          |  356 ++++++++++++++++++++
 sc/source/ui/Accessibility/DrawModelBroadcaster.cxx |    4 
 sc/source/ui/inc/DrawModelBroadcaster.hxx           |    4 
 3 files changed, 360 insertions(+), 4 deletions(-)

New commits:
commit 89ea9340aca77a87ef10785a734201d2f400a933
Author:     Noel Grandin <noel.grandin at collabora.co.uk>
AuthorDate: Tue Aug 20 13:46:01 2019 +0200
Commit:     Noel Grandin <noel.grandin at collabora.co.uk>
CommitDate: Tue Aug 20 20:35:01 2019 +0200

    tdf#119388 speed up listener broadcast
    
    when deleting columns with lots of shapes. The UNO_QUERY is expensive in
    this case, so create a new comphelper::OInterfaceContainerHelper3 that
    knows what type the listener interface is.
    
    Takes the time from 47s to 41s for me.
    
    Change-Id: Id575a59af8505fbd3b0638fd5224e70fd556215f
    Reviewed-on: https://gerrit.libreoffice.org/77824
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>

diff --git a/include/comphelper/interfacecontainer3.hxx b/include/comphelper/interfacecontainer3.hxx
new file mode 100644
index 000000000000..087dc45e12cc
--- /dev/null
+++ b/include/comphelper/interfacecontainer3.hxx
@@ -0,0 +1,356 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_COMPHELPER_INTERFACECONTAINER3_H
+#define INCLUDED_COMPHELPER_INTERFACECONTAINER3_H
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/EventObject.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <comphelper/comphelperdllapi.h>
+#include <o3tl/cow_wrapper.hxx>
+#include <vector>
+
+namespace com
+{
+namespace sun
+{
+namespace star
+{
+namespace uno
+{
+class XInterface;
+}
+}
+}
+}
+namespace osl
+{
+class Mutex;
+}
+
+/** */ //for docpp
+namespace comphelper
+{
+template <class ListenerT> class OInterfaceContainerHelper3;
+/**
+  This is the iterator of an InterfaceContainerHelper. Typically
+  one constructs an instance on the stack for one firing session.
+  It is not allowed to assign or copy an instance of this class.
+
+  @tparam ListenerT UNO event listener type
+  @see OInterfaceContainerHelper
+ */
+template <class ListenerT> class OInterfaceIteratorHelper3
+{
+public:
+    /**
+       Create an iterator over the elements of the container. The iterator
+       copies the elements of the container. A change to the container
+       during the lifetime of an iterator is allowed and does not
+       affect the iterator-instance. The iterator and the container take cares
+       themself for concurrent access, no additional guarding is necessary.
+
+       Remark: The copy is on demand. The iterator copy the elements only if the container
+       change the contents..
+
+       @param rCont the container of the elements.
+     */
+    OInterfaceIteratorHelper3(OInterfaceContainerHelper3<ListenerT>& rCont_)
+        : rCont(rCont_)
+        , maData(rCont.maData)
+        , nRemain(maData->size())
+    {
+    }
+
+    /** Return true, if there are more elements in the iterator. */
+    bool hasMoreElements() const { return nRemain != 0; }
+    /** Return the next element of the iterator. Calling this method if
+        hasMoreElements() has returned false, is an error.
+     */
+    css::uno::Reference<ListenerT> const& next();
+
+    /** Removes the current element (the last one returned by next())
+        from the underlying container. Calling this method before
+        next() has been called or calling it twice with no next()
+        in between is an error.
+    */
+    void remove();
+
+private:
+    OInterfaceContainerHelper3<ListenerT>& rCont;
+    o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>> maData;
+    sal_Int32 nRemain;
+
+    OInterfaceIteratorHelper3(const OInterfaceIteratorHelper3&) = delete;
+    OInterfaceIteratorHelper3& operator=(const OInterfaceIteratorHelper3&) = delete;
+};
+
+template <class ListenerT>
+const css::uno::Reference<ListenerT>& OInterfaceIteratorHelper3<ListenerT>::next()
+{
+    nRemain--;
+    return (*maData)[nRemain];
+}
+
+template <class ListenerT> void OInterfaceIteratorHelper3<ListenerT>::remove()
+{
+    rCont.removeInterface((*maData)[nRemain]);
+}
+
+/**
+  A container of interfaces. To access the elements use an iterator.
+  This implementation is thread safe.
+
+  @tparam ListenerT UNO event listener type
+  @see OInterfaceIteratorHelper
+ */
+template <class ListenerT> class OInterfaceContainerHelper3
+{
+public:
+    /**
+       Create an interface container.
+
+       @param rMutex    the mutex to protect multi thread access.
+       The lifetime must be longer than the lifetime
+       of this object.
+     */
+    OInterfaceContainerHelper3(::osl::Mutex& rMutex_)
+        : rMutex(rMutex_)
+    {
+    }
+    /**
+      Return the number of Elements in the container. Only useful if you have acquired
+      the mutex.
+     */
+    sal_Int32 getLength() const;
+
+    /**
+      Return all interfaces added to this container.
+     **/
+    std::vector<css::uno::Reference<ListenerT>> getElements() const;
+
+    /** Inserts an element into the container.  The position is not specified, thus it is not
+        specified in which order events are fired.
+
+        @attention
+        If you add the same interface more than once, then it will be added to the elements list
+        more than once and thus if you want to remove that interface from the list, you have to call
+        removeInterface() the same number of times.
+        In the latter case, you will also get events fired more than once (if the interface is a
+        listener interface).
+
+        @param rxIFace
+               interface to be added; it is allowed to
+               the same interface more than once
+        @return
+                the new count of elements in the container
+    */
+    sal_Int32 addInterface(const css::uno::Reference<ListenerT>& rxIFace);
+    /** Removes an element from the container.  It uses interface equality to remove the interface.
+
+        @param rxIFace
+               interface to be removed
+        @return
+                the new count of elements in the container
+    */
+    sal_Int32 removeInterface(const css::uno::Reference<ListenerT>& rxIFace);
+    /**
+      Call disposing on all object in the container that
+      support XEventListener. Then clear the container.
+     */
+    void disposeAndClear(const css::lang::EventObject& rEvt);
+    /**
+      Clears the container without calling disposing().
+     */
+    void clear();
+
+    /** Executes a functor for each contained listener of specified type, e.g.
+        <code>forEach<awt::XPaintListener>(...</code>.
+
+        If a css::lang::DisposedException occurs which relates to
+        the called listener, then that listener is removed from the container.
+
+        @tparam FuncT unary functor type, let your compiler deduce this for you
+        @param func unary functor object expecting an argument of type
+                    css::uno::Reference<ListenerT>
+    */
+    template <typename FuncT> inline void forEach(FuncT const& func);
+
+    /** Calls a UNO listener method for each contained listener.
+
+        The listener method must take a single argument of type EventT,
+        and return <code>void</code>.
+
+        If a css::lang::DisposedException occurs which relates to
+        the called listener, then that listener is removed from the container.
+
+        @tparam EventT event type, let your compiler deduce this for you
+        @param NotificationMethod
+            Pointer to a method of a ListenerT interface.
+        @param Event
+            Event to notify to all contained listeners
+
+        Example:
+ at code
+    awt::PaintEvent aEvent( static_cast< cppu::OWeakObject* >( this ), ... );
+    listeners.notifyEach( &XPaintListener::windowPaint, aEvent );
+ at endcode
+    */
+    template <typename EventT>
+    inline void notifyEach(void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&),
+                           const EventT& Event);
+
+private:
+    friend class OInterfaceIteratorHelper3<ListenerT>;
+    o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>> maData;
+    ::osl::Mutex& rMutex;
+    OInterfaceContainerHelper3(const OInterfaceContainerHelper3&) = delete;
+    OInterfaceContainerHelper3& operator=(const OInterfaceContainerHelper3&) = delete;
+
+private:
+    template <typename EventT> class NotifySingleListener
+    {
+    private:
+        typedef void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&);
+        NotificationMethod const m_pMethod;
+        const EventT& m_rEvent;
+
+    public:
+        NotifySingleListener(NotificationMethod method, const EventT& event)
+            : m_pMethod(method)
+            , m_rEvent(event)
+        {
+        }
+
+        void operator()(const css::uno::Reference<ListenerT>& listener) const
+        {
+            (listener.get()->*m_pMethod)(m_rEvent);
+        }
+    };
+};
+
+template <class T>
+template <typename FuncT>
+inline void OInterfaceContainerHelper3<T>::forEach(FuncT const& func)
+{
+    OInterfaceIteratorHelper3<T> iter(*this);
+    while (iter.hasMoreElements())
+    {
+        auto xListener = iter.next();
+        try
+        {
+            func(xListener);
+        }
+        catch (css::lang::DisposedException const& exc)
+        {
+            if (exc.Context == xListener)
+                iter.remove();
+        }
+    }
+}
+
+template <class ListenerT>
+template <typename EventT>
+inline void OInterfaceContainerHelper3<ListenerT>::notifyEach(
+    void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&), const EventT& Event)
+{
+    forEach<NotifySingleListener<EventT>>(NotifySingleListener<EventT>(NotificationMethod, Event));
+}
+
+template <class ListenerT> sal_Int32 OInterfaceContainerHelper3<ListenerT>::getLength() const
+{
+    osl::MutexGuard aGuard(rMutex);
+    return maData->size();
+}
+
+template <class ListenerT>
+std::vector<css::uno::Reference<ListenerT>>
+OInterfaceContainerHelper3<ListenerT>::getElements() const
+{
+    std::vector<css::uno::Reference<ListenerT>> rVec;
+    osl::MutexGuard aGuard(rMutex);
+    rVec = *maData;
+    return rVec;
+}
+
+template <class ListenerT>
+sal_Int32
+OInterfaceContainerHelper3<ListenerT>::addInterface(const css::uno::Reference<ListenerT>& rListener)
+{
+    assert(rListener.is());
+    osl::MutexGuard aGuard(rMutex);
+
+    maData->push_back(rListener);
+    return maData->size();
+}
+
+template <class ListenerT>
+sal_Int32 OInterfaceContainerHelper3<ListenerT>::removeInterface(
+    const css::uno::Reference<ListenerT>& rListener)
+{
+    assert(rListener.is());
+    osl::MutexGuard aGuard(rMutex);
+
+    // It is not valid to compare the pointer directly, but it's faster.
+    auto it = std::find_if(maData->begin(), maData->end(),
+                           [&rListener](const css::uno::Reference<css::uno::XInterface>& rItem) {
+                               return rItem.get() == rListener.get();
+                           });
+
+    // interface not found, use the correct compare method
+    if (it == maData->end())
+        it = std::find(maData->begin(), maData->end(), rListener);
+
+    if (it != maData->end())
+        maData->erase(it);
+
+    return maData->size();
+}
+
+template <class ListenerT>
+void OInterfaceContainerHelper3<ListenerT>::disposeAndClear(const css::lang::EventObject& rEvt)
+{
+    osl::ClearableMutexGuard aGuard(rMutex);
+    OInterfaceIteratorHelper3<ListenerT> aIt(*this);
+    maData->clear();
+    aGuard.clear();
+    while (aIt.hasMoreElements())
+    {
+        try
+        {
+            aIt.next()->disposing(rEvt);
+        }
+        catch (css::uno::RuntimeException&)
+        {
+            // be robust, if e.g. a remote bridge has disposed already.
+            // there is no way to delegate the error to the caller :o(.
+        }
+    }
+}
+
+template <class ListenerT> void OInterfaceContainerHelper3<ListenerT>::clear()
+{
+    osl::MutexGuard aGuard(rMutex);
+    maData->clear();
+}
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/DrawModelBroadcaster.cxx b/sc/source/ui/Accessibility/DrawModelBroadcaster.cxx
index 0135865c361a..4cf1567856c5 100644
--- a/sc/source/ui/Accessibility/DrawModelBroadcaster.cxx
+++ b/sc/source/ui/Accessibility/DrawModelBroadcaster.cxx
@@ -60,10 +60,10 @@ void ScDrawModelBroadcaster::Notify( SfxBroadcaster&,
     if( !SvxUnoDrawMSFactory::createEvent( mpDrawModel, pSdrHint, aEvent ) )
         return;
 
-    ::comphelper::OInterfaceIteratorHelper2 aIter( maEventListeners );
+    ::comphelper::OInterfaceIteratorHelper3 aIter( maEventListeners );
     while( aIter.hasMoreElements() )
     {
-        uno::Reference < document::XEventListener > xListener( aIter.next(), uno::UNO_QUERY );
+        const uno::Reference < document::XEventListener >& xListener = aIter.next();
         try
         {
             xListener->notifyEvent( aEvent );
diff --git a/sc/source/ui/inc/DrawModelBroadcaster.hxx b/sc/source/ui/inc/DrawModelBroadcaster.hxx
index 6c014da85713..6a967a075075 100644
--- a/sc/source/ui/inc/DrawModelBroadcaster.hxx
+++ b/sc/source/ui/inc/DrawModelBroadcaster.hxx
@@ -21,7 +21,7 @@
 #define INCLUDED_SC_SOURCE_UI_INC_DRAWMODELBROADCASTER_HXX
 
 #include <svl/lstner.hxx>
-#include <comphelper/interfacecontainer2.hxx>
+#include <comphelper/interfacecontainer3.hxx>
 #include <cppuhelper/implbase.hxx>
 #include <com/sun/star/document/XEventBroadcaster.hpp>
 
@@ -31,7 +31,7 @@ class ScDrawModelBroadcaster : public SfxListener,
     public ::cppu::WeakImplHelper< css::document::XEventBroadcaster >
 {
     mutable ::osl::Mutex maListenerMutex;
-    ::comphelper::OInterfaceContainerHelper2 maEventListeners;
+    ::comphelper::OInterfaceContainerHelper3<css::document::XEventListener> maEventListeners;
     SdrModel *mpDrawModel;
 
 public:


More information about the Libreoffice-commits mailing list