include/svl/itemset.hxx         |    1 +
 sc/inc/patattr.hxx              |    3 +++
 sc/source/core/data/patattr.cxx |   14 +++++++++++++-
 svl/source/items/itemset.cxx    |   19 +++++++++++++++++++
 4 files changed, 36 insertions(+), 1 deletion(-)

New commits:
commit 044885e896a441c96a6934b10cbb723fabcf262d
Author:     Noel Grandin <[email protected]>
AuthorDate: Sun Dec 21 19:55:04 2025 +0200
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Sat Dec 27 04:26:54 2025 +0100

    tdf#166684 use hashing in CellAttributeHelper::registerAndCheck
    
    reduces load time from 1m11s to 33s.
    
    Change-Id: I911c101eb8692bf678e6f7147e64e503e9f2bf0a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196062
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Tomaž Vajngerl <[email protected]>

diff --git a/include/svl/itemset.hxx b/include/svl/itemset.hxx
index 9a83cad194d3..ac4050f63a99 100644
--- a/include/svl/itemset.hxx
+++ b/include/svl/itemset.hxx
@@ -255,6 +255,7 @@ public:
     const SfxItemSet*           GetParent() const { return m_pParent; }
 
     bool                        operator==(const SfxItemSet &) const;
+    size_t                      GetHashCode() const;
 
     /** Compare possibly ignoring SfxItemPool pointer.
 
diff --git a/sc/inc/patattr.hxx b/sc/inc/patattr.hxx
index ab09e64ace83..293f132963ce 100644
--- a/sc/inc/patattr.hxx
+++ b/sc/inc/patattr.hxx
@@ -130,6 +130,7 @@ class SAL_DLLPUBLIC_RTTI ScPatternAttr final
     friend class CellAttributeHelper;
 
     SfxItemSet                  maLocalSfxItemSet;
+    mutable std::optional<size_t> moHashCode;
     std::optional<OUString>     moName;
     mutable std::optional<bool> mxVisible;
     mutable std::optional<sal_uInt32> mxNumberFormatKey;
@@ -149,6 +150,7 @@ public:
     SC_DLLPUBLIC ~ScPatternAttr();
 
     bool operator==(const ScPatternAttr& rCmp) const;
+    size_t GetHashCode() const { if (!moHashCode) CalcHashCode(); return 
*moHashCode; }
 
     // version that allows nullptrs
     SC_DLLPUBLIC static bool areSame(const ScPatternAttr* pItem1, const 
ScPatternAttr* pItem2);
@@ -287,6 +289,7 @@ private:
     sal_uInt32              GetNumberFormatKey() const;
     LanguageType            GetLanguageType() const;
     void                    InvalidateCaches();
+    void                    CalcHashCode() const;
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/patattr.cxx b/sc/source/core/data/patattr.cxx
index 3e8f671bb9d7..1baf6cf913ae 100644
--- a/sc/source/core/data/patattr.cxx
+++ b/sc/source/core/data/patattr.cxx
@@ -115,12 +115,14 @@ const ScPatternAttr* 
CellAttributeHelper::registerAndCheck(const ScPatternAttr&
     }
     const OUString* pCandidateStyleName = rCandidate.GetStyleName();
     auto it = maRegisteredCellAttributes.lower_bound(pCandidateStyleName);
+    const size_t nCandidateHashCode = rCandidate.GetHashCode();
     for (; it != maRegisteredCellAttributes.end(); ++it)
     {
         const ScPatternAttr* pCheck = *it;
         if (CompareStringPtr(pCheck->GetStyleName(), pCandidateStyleName) != 0)
             break;
-        if (ScPatternAttr::areSame(pCheck, &rCandidate))
+        if (nCandidateHashCode == pCheck->GetHashCode()
+            && ScPatternAttr::areSame(pCheck, &rCandidate))
         {
             pCheck->mnRefCount++;
             if (bPassingOwnership)
@@ -472,6 +474,15 @@ bool ScPatternAttr::operator==(const ScPatternAttr& rCmp) 
const
     return maLocalSfxItemSet == rCmp.maLocalSfxItemSet;
 }
 
+void ScPatternAttr::CalcHashCode() const
+{
+    size_t nHash = 0;
+    if (const OUString* pName = GetStyleName())
+        nHash = pName->hashCode();
+    o3tl::hash_combine(nHash, maLocalSfxItemSet.GetHashCode());
+    moHashCode = nHash;
+}
+
 bool ScPatternAttr::areSame(const ScPatternAttr* pItem1, const ScPatternAttr* 
pItem2)
 {
     if (pItem1 == pItem2)
@@ -1864,6 +1875,7 @@ void ScPatternAttr::InvalidateCaches()
     mxVisible.reset();
     mxNumberFormatKey.reset();
     mxLanguageType.reset();
+    moHashCode.reset();
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svl/source/items/itemset.cxx b/svl/source/items/itemset.cxx
index 3c0d1cbd4783..122e22c2ab78 100644
--- a/svl/source/items/itemset.cxx
+++ b/svl/source/items/itemset.cxx
@@ -26,6 +26,7 @@
 #include <unordered_map>
 
 #include <libxml/xmlwriter.h>
+#include <o3tl/hash_combine.hxx>
 
 #include <sal/log.hxx>
 #include <svl/itemset.hxx>
@@ -1288,6 +1289,24 @@ bool SfxItemSet::Equals(const SfxItemSet &rCmp, bool 
bComparePool) const
     return true;
 }
 
+size_t SfxItemSet::GetHashCode() const
+{
+    size_t seed = 0;
+
+    for (PoolItemMap::const_iterator it(m_aPoolItemMap.begin()); it != 
m_aPoolItemMap.end(); it++)
+    {
+        const sal_uInt16 nWhich = it->first;
+        const SfxPoolItem *pItem = it->second;
+
+        o3tl::hash_combine(seed, nWhich);
+        if (!IsInvalidItem(pItem) && !IsDisabledItem(pItem)
+            && pItem && pItem->supportsHashCode())
+            o3tl::hash_combine(seed, pItem->hashCode());
+    }
+
+    return seed;
+}
+
 std::unique_ptr<SfxItemSet> SfxItemSet::Clone(bool bItems, SfxItemPool 
*pToPool ) const
 {
     if (pToPool && pToPool != GetPool())

Reply via email to