include/svl/itemset.hxx      |    8 ++++++
 include/svl/whiter.hxx       |   22 +++++++++++------
 svl/source/items/itemset.cxx |   55 +++++++++++++++++++++++++++++++------------
 svl/source/items/whiter.cxx  |   49 +++++++++++++++++++++++---------------
 4 files changed, 93 insertions(+), 41 deletions(-)

New commits:
commit 87a932120d5f146933ed3bcc16c0f47dab90fd4b
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Thu May 26 15:19:42 2022 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Sat May 28 16:00:09 2022 +0200

    ofz#24932-1 speed up GetItemState when iterating
    
    by having SfxWhichIter track the current position in
    the m_ppItems table, which means GetItemState does
    not need to traverse the ranges table to find the
    item position.
    
    shaves 75% off the time of
    ./instdir/program/soffice.bin --calc --convert-to pdf
        ~/Downloads/ofz24932-1.rtf
    
    Change-Id: Ib5fe61c75ca05bc2f1932e84b57ccfa55f8b7f74
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135023
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/include/svl/itemset.hxx b/include/svl/itemset.hxx
index 7b535fb93d6f..746ba8448afb 100644
--- a/include/svl/itemset.hxx
+++ b/include/svl/itemset.hxx
@@ -23,6 +23,7 @@
 #include <cassert>
 #include <cstddef>
 #include <memory>
+#include <optional>
 #include <utility>
 
 #include <svl/svldllapi.h>
@@ -35,6 +36,7 @@ class SfxItemPool;
 class SAL_WARN_UNUSED SVL_DLLPUBLIC SfxItemSet
 {
     friend class SfxItemIter;
+    friend class SfxWhichIter;
 
     SfxItemPool*      m_pPool;         ///< pool that stores the items
     const SfxItemSet* m_pParent;       ///< derivation
@@ -223,6 +225,12 @@ public:
     bool                        Equals(const SfxItemSet &, bool bComparePool) 
const;
 
     void dumpAsXml(xmlTextWriterPtr pWriter) const;
+
+private:
+    SfxItemState  GetItemStateImpl( sal_uInt16 nWhich,
+                                bool bSrchInParent,
+                                const SfxPoolItem **ppItem,
+                                std::optional<sal_uInt16> oItemsOffsetHint) 
const;
 };
 
 inline void SfxItemSet::SetParent( const SfxItemSet* pNew )
diff --git a/include/svl/whiter.hxx b/include/svl/whiter.hxx
index c4a49a06b622..df8c6fea79f2 100644
--- a/include/svl/whiter.hxx
+++ b/include/svl/whiter.hxx
@@ -16,19 +16,27 @@
  *   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_SVL_WHITER_HXX
-#define INCLUDED_SVL_WHITER_HXX
+#pragma once
 
 #include <svl/svldllapi.h>
 #include <svl/whichranges.hxx>
 
 class SfxItemSet;
+class SfxPoolItem;
+enum class SfxItemState;
 
+/**
+ * Iterates over the which ids and the pool items arrays together (which are 
stored in parallel arrays).
+ * Primarily so that we can call GetItemSet on the SfxItemSet and pass in a 
hint, which avoids
+ * searching the array the SfxItemSet, which speeds up GetItemState greatly.
+ */
 class SVL_DLLPUBLIC SfxWhichIter
 {
-    const WhichRangesContainer& pStart;
-    const WhichPair* pRanges;
-    sal_uInt16 nOffset;
+    const SfxItemSet& m_rItemSet;
+    const WhichPair* m_pCurrentWhichPair;
+    sal_uInt16 m_nOffsetFromStartOfCurrentWhichPair;
+    /// Offset into m_ppItems array in SfxItemSet
+    sal_uInt16 m_nItemsOffset;
 
 public:
     SfxWhichIter(const SfxItemSet& rSet);
@@ -36,8 +44,8 @@ public:
     sal_uInt16 GetCurWhich() const;
     sal_uInt16 NextWhich();
     sal_uInt16 FirstWhich();
+    SfxItemState GetItemState(bool bSrchInParent = true,
+                              const SfxPoolItem** ppItem = nullptr) const;
 };
 
-#endif
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svl/source/items/itemset.cxx b/svl/source/items/itemset.cxx
index 2d90ab16eac7..c96bac69c54d 100644
--- a/svl/source/items/itemset.cxx
+++ b/svl/source/items/itemset.cxx
@@ -308,41 +308,66 @@ void SfxItemSet::InvalidateAllItems()
 SfxItemState SfxItemSet::GetItemState( sal_uInt16 nWhich,
                                         bool bSrchInParent,
                                         const SfxPoolItem **ppItem ) const
+{
+    return GetItemStateImpl(nWhich, bSrchInParent, ppItem, std::nullopt);
+}
+
+SfxItemState SfxItemSet::GetItemStateImpl( sal_uInt16 nWhich,
+                                           bool bSrchInParent,
+                                           const SfxPoolItem **ppItem,
+                                           std::optional<sal_uInt16> 
oItemsOffsetHint) const
 {
     // Find the range in which the Which is located
     const SfxItemSet* pCurrentSet = this;
     SfxItemState eRet = SfxItemState::UNKNOWN;
     do
     {
-        SfxPoolItem const** ppFnd = pCurrentSet->m_ppItems;
-        for (const WhichPair& rPair : pCurrentSet->m_pWhichRanges)
+        SfxPoolItem const** pFoundOne = nullptr;
+        if (oItemsOffsetHint)
+        {
+            pFoundOne = pCurrentSet->m_ppItems + *oItemsOffsetHint;
+            assert(!*pFoundOne || IsInvalidItem(*pFoundOne) || 
(*pFoundOne)->IsVoidItem() || (*pFoundOne)->Which() == nWhich);
+            oItemsOffsetHint.reset(); // in case we need to search parent
+        }
+        else
         {
-            if ( rPair.first <= nWhich && nWhich <= rPair.second )
+            SfxPoolItem const** ppFnd = pCurrentSet->m_ppItems;
+            for (const WhichPair& rPair : pCurrentSet->m_pWhichRanges)
             {
-                // Within this range
-                ppFnd += nWhich - rPair.first;
-                if ( !*ppFnd )
+                if ( rPair.first <= nWhich && nWhich <= rPair.second )
                 {
-                    eRet = SfxItemState::DEFAULT;
-                    if( !bSrchInParent )
-                        return eRet; // Not present
-                    break; // Keep searching in the parents!
+                    // Within this range
+                    pFoundOne = ppFnd + nWhich - rPair.first;
+                    break;
                 }
+                ppFnd += rPair.second - rPair.first + 1;
+            }
+        }
 
-                if ( IsInvalidItem(*ppFnd) )
+        if (pFoundOne)
+        {
+            if ( !*pFoundOne )
+            {
+                eRet = SfxItemState::DEFAULT;
+                if( !bSrchInParent )
+                    return eRet; // Not present
+                // Keep searching in the parents!
+            }
+            else
+            {
+                if ( IsInvalidItem(*pFoundOne) )
                     // Different ones are present
                     return SfxItemState::DONTCARE;
 
-                if ( (*ppFnd)->IsVoidItem() )
+                if ( (*pFoundOne)->IsVoidItem() )
                     return SfxItemState::DISABLED;
 
                 if (ppItem)
                 {
-                    *ppItem = *ppFnd;
+                    *ppItem = *pFoundOne;
                 }
                 return SfxItemState::SET;
             }
-            ppFnd += rPair.second - rPair.first + 1;
         }
         if (!bSrchInParent)
             break;
@@ -726,7 +751,7 @@ bool SfxItemSet::Set
                 continue;
             }
             const SfxPoolItem* pItem;
-            if( SfxItemState::SET == rSet.GetItemState( nWhich1, true, &pItem 
) )
+            if( SfxItemState::SET == aIter2.GetItemState( true, &pItem ) )
                 bRet |= nullptr != Put( *pItem, pItem->Which() );
             nWhich1 = aIter1.NextWhich();
             nWhich2 = aIter2.NextWhich();
diff --git a/svl/source/items/whiter.cxx b/svl/source/items/whiter.cxx
index 59f2790a530c..707349c70ea5 100644
--- a/svl/source/items/whiter.cxx
+++ b/svl/source/items/whiter.cxx
@@ -17,46 +17,57 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
  */
 
-
-#include <svl/whiter.hxx>
 #include <svl/itemset.hxx>
+#include <svl/whiter.hxx>
 
-SfxWhichIter::SfxWhichIter( const SfxItemSet& rSet ):
-    pStart(rSet.GetRanges()),
-    pRanges(pStart.begin()),
-    nOffset(0)
+SfxWhichIter::SfxWhichIter(const SfxItemSet& rSet)
+    : m_rItemSet(rSet)
+    , m_pCurrentWhichPair(rSet.m_pWhichRanges.begin())
+    , m_nOffsetFromStartOfCurrentWhichPair(0)
+    , m_nItemsOffset(0)
 {
 }
 
 sal_uInt16 SfxWhichIter::GetCurWhich() const
 {
-    if ( pRanges >= (pStart.begin() + pStart.size()) )
+    const WhichRangesContainer& rWhichRanges = m_rItemSet.m_pWhichRanges;
+    if (m_pCurrentWhichPair >= (rWhichRanges.begin() + rWhichRanges.size()))
         return 0;
-    return pRanges->first + nOffset;
+    return m_pCurrentWhichPair->first + m_nOffsetFromStartOfCurrentWhichPair;
 }
 
 sal_uInt16 SfxWhichIter::NextWhich()
 {
-    if ( pRanges >= (pStart.begin() + pStart.size()) )
+    const WhichRangesContainer& rWhichRanges = m_rItemSet.m_pWhichRanges;
+    if (m_pCurrentWhichPair >= (rWhichRanges.begin() + rWhichRanges.size()))
         return 0;
 
-    const sal_uInt16 nLastWhich = pRanges->first + nOffset;
-    ++nOffset;
-    if (pRanges->second == nLastWhich)
+    const sal_uInt16 nLastWhich = m_pCurrentWhichPair->first + 
m_nOffsetFromStartOfCurrentWhichPair;
+    ++m_nOffsetFromStartOfCurrentWhichPair;
+    if (m_pCurrentWhichPair->second == nLastWhich)
     {
-        ++pRanges;
-        nOffset = 0;
+        m_nItemsOffset += m_pCurrentWhichPair->second - 
m_pCurrentWhichPair->first + 1;
+        ++m_pCurrentWhichPair;
+        m_nOffsetFromStartOfCurrentWhichPair = 0;
     }
-    if ( pRanges >= (pStart.begin() + pStart.size()) )
+    if (m_pCurrentWhichPair >= (rWhichRanges.begin() + rWhichRanges.size()))
         return 0;
-    return pRanges->first + nOffset;
+    return m_pCurrentWhichPair->first + m_nOffsetFromStartOfCurrentWhichPair;
 }
 
 sal_uInt16 SfxWhichIter::FirstWhich()
 {
-    pRanges = pStart.begin();
-    nOffset = 0;
-    return pRanges->first;
+    m_pCurrentWhichPair = m_rItemSet.m_pWhichRanges.begin();
+    m_nOffsetFromStartOfCurrentWhichPair = 0;
+    m_nItemsOffset = 0;
+    return m_pCurrentWhichPair->first;
+}
+
+SfxItemState SfxWhichIter::GetItemState(bool bSrchInParent, const 
SfxPoolItem** ppItem) const
+{
+    sal_uInt16 nWhich = m_pCurrentWhichPair->first + 
m_nOffsetFromStartOfCurrentWhichPair;
+    sal_uInt16 nItemsOffsetHint = m_nItemsOffset + 
m_nOffsetFromStartOfCurrentWhichPair;
+    return m_rItemSet.GetItemStateImpl(nWhich, bSrchInParent, ppItem, 
nItemsOffsetHint);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to