include/svl/style.hxx           |    3 
 sc/inc/patattr.hxx              |   17 +---
 sc/source/core/data/patattr.cxx |  170 +++++++++++++++++++---------------------
 svl/source/items/style.cxx      |    5 -
 4 files changed, 90 insertions(+), 105 deletions(-)

New commits:
commit a6812f5dab4b4eab0dca92a0556a70317aeca80d
Author:     Noel Grandin <[email protected]>
AuthorDate: Mon Dec 22 10:30:56 2025 +0200
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Sat Dec 27 04:27:30 2025 +0100

    tdf#166684 inline SfxStyleSheetIterator::GetSearchFamily
    
    which is a little hot here, and this is just a getter method.
    Shaves about 1% off.
    
    Change-Id: I94fcdbb35e1be9cbc446f7f7709eaa67d21d0d48
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196064
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Tomaž Vajngerl <[email protected]>

diff --git a/include/svl/style.hxx b/include/svl/style.hxx
index c0aa959c5083..e4746d0e1bc9 100644
--- a/include/svl/style.hxx
+++ b/include/svl/style.hxx
@@ -202,7 +202,8 @@ public:
     SfxStyleSheetIterator(const SfxStyleSheetBasePool *pBase,
                           SfxStyleFamily eFam, SfxStyleSearchBits 
n=SfxStyleSearchBits::All );
     SfxStyleSearchBits GetSearchMask() const;
-    SfxStyleFamily GetSearchFamily() const;
+    SfxStyleFamily GetSearchFamily() const { return nSearchFamily; }
+
     virtual sal_Int32 Count();
     virtual SfxStyleSheetBase *operator[](sal_Int32 nIdx);
     virtual SfxStyleSheetBase* First();
diff --git a/svl/source/items/style.cxx b/svl/source/items/style.cxx
index 26fefac02922..efa4881434cd 100644
--- a/svl/source/items/style.cxx
+++ b/svl/source/items/style.cxx
@@ -365,11 +365,6 @@ OUString SfxStyleSheetBase::GetDescription( MapUnit 
eMetric )
     return aDesc.makeStringAndClear();
 }
 
-SfxStyleFamily SfxStyleSheetIterator::GetSearchFamily() const
-{
-    return nSearchFamily;
-}
-
 inline bool SfxStyleSheetIterator::IsTrivialSearch() const
 {
     return (( nMask & SfxStyleSearchBits::AllVisible ) == 
SfxStyleSearchBits::AllVisible) &&
commit b0920fbf83957a245292ea23840d79e0c6385429
Author:     Noel Grandin <[email protected]>
AuthorDate: Mon Dec 22 09:19:59 2025 +0200
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Sat Dec 27 04:27:16 2025 +0100

    tdf#166684 use unordered_map/sorted_vector in registerAndCheck()
    
    which is little more memory expensive, but about 10% more efficient in load
    time here.
    
    Change-Id: If1cfb7dfe3b6a70f5acf8766db4b83eb386030bf
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196063
    Reviewed-by: Tomaž Vajngerl <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/sc/inc/patattr.hxx b/sc/inc/patattr.hxx
index 293f132963ce..263215014cc9 100644
--- a/sc/inc/patattr.hxx
+++ b/sc/inc/patattr.hxx
@@ -25,11 +25,12 @@
 #include <svl/languageoptions.hxx>
 #include <tools/degree.hxx>
 #include <editeng/svxenum.hxx>
+#include <o3tl/sorted_vector.hxx>
 #include "scdllapi.h"
 #include "fonthelper.hxx"
 #include "scitems.hxx"
 #include "attrib.hxx"
-#include <set>
+#include <unordered_map>
 
 namespace vcl { class Font; }
 namespace model { class ComplexColor; }
@@ -62,20 +63,16 @@ class SC_DLLPUBLIC CellAttributeHelper final
     // Data structure chosen so that
     // (a) we can find by name
     // (b) we can erase quickly, by using name and pointer.
-    // so we sort the set first by name, and then by pointer.
-    struct RegisteredAttrSetLess
+    // (c) scanning through all the entries with the same name is cheap
+    struct RegisteredAttrMapHash
     {
-        bool operator()(const ScPatternAttr* lhs, const ScPatternAttr* rhs) 
const;
-        // so we can search in std::set without a ScPatternAttr
-        using is_transparent = void;
-        bool operator()(const ScPatternAttr* lhs, const OUString* rhs) const;
-        bool operator()(const OUString* lhs, const ScPatternAttr* rhs) const;
+        size_t operator()(const std::optional<OUString>&) const;
     };
-    typedef std::set<const ScPatternAttr*, RegisteredAttrSetLess> 
RegisteredAttrSet;
+    typedef std::unordered_map<std::optional<OUString>, 
o3tl::sorted_vector<const ScPatternAttr*>, RegisteredAttrMapHash> 
RegisteredAttrMap;
 
     SfxItemPool&                                        mrSfxItemPool;
     mutable ScPatternAttr*                              mpDefaultCellAttribute;
-    mutable RegisteredAttrSet                           
maRegisteredCellAttributes;
+    mutable RegisteredAttrMap                           
maRegisteredCellAttributes;
     mutable const ScPatternAttr*                        mpLastHit;
     mutable sal_uInt64                                  mnCurrentMaxKey;
 
diff --git a/sc/source/core/data/patattr.cxx b/sc/source/core/data/patattr.cxx
index 1baf6cf913ae..bf47b22acbca 100644
--- a/sc/source/core/data/patattr.cxx
+++ b/sc/source/core/data/patattr.cxx
@@ -80,17 +80,6 @@ CellAttributeHelper::~CellAttributeHelper()
     delete mpDefaultCellAttribute;
 }
 
-static int CompareStringPtr(const OUString* lhs, const OUString* rhs)
-{
-    if (lhs == rhs)
-        return 0;
-    if (lhs && rhs)
-        return (*lhs).compareTo(*rhs);
-    if (!lhs && rhs)
-        return -1;
-    return 1;
-}
-
 const ScPatternAttr* CellAttributeHelper::registerAndCheck(const 
ScPatternAttr& rCandidate, bool bPassingOwnership) const
 {
     if (&rCandidate == &getDefaultCellAttribute())
@@ -114,28 +103,29 @@ const ScPatternAttr* 
CellAttributeHelper::registerAndCheck(const ScPatternAttr&
         return mpLastHit;
     }
     const OUString* pCandidateStyleName = rCandidate.GetStyleName();
-    auto it = maRegisteredCellAttributes.lower_bound(pCandidateStyleName);
-    const size_t nCandidateHashCode = rCandidate.GetHashCode();
-    for (; it != maRegisteredCellAttributes.end(); ++it)
+    auto it = maRegisteredCellAttributes.find(pCandidateStyleName ? 
std::optional<OUString>(*pCandidateStyleName) : std::nullopt);
+    if (it != maRegisteredCellAttributes.end())
     {
-        const ScPatternAttr* pCheck = *it;
-        if (CompareStringPtr(pCheck->GetStyleName(), pCandidateStyleName) != 0)
-            break;
-        if (nCandidateHashCode == pCheck->GetHashCode()
-            && ScPatternAttr::areSame(pCheck, &rCandidate))
+        const size_t nCandidateHashCode = rCandidate.GetHashCode();
+        for (const ScPatternAttr* pCheck : it->second)
         {
-            pCheck->mnRefCount++;
-            if (bPassingOwnership)
-                delete &rCandidate;
-            mpLastHit = pCheck;
-            return pCheck;
+            if (nCandidateHashCode == pCheck->GetHashCode()
+                && ScPatternAttr::areSame(pCheck, &rCandidate))
+            {
+                pCheck->mnRefCount++;
+                if (bPassingOwnership)
+                    delete &rCandidate;
+                mpLastHit = pCheck;
+                return pCheck;
+            }
         }
     }
 
     const ScPatternAttr* pCandidate(bPassingOwnership ? &rCandidate : new 
ScPatternAttr(rCandidate));
     pCandidate->mnRefCount++;
     const_cast<ScPatternAttr*>(pCandidate)->SetPAKey(mnCurrentMaxKey++);
-    maRegisteredCellAttributes.insert(pCandidate);
+    const OUString* pStyleName = pCandidate->GetStyleName();
+    maRegisteredCellAttributes[pStyleName ? 
std::optional<OUString>(*pStyleName) : std::nullopt].insert(pCandidate);
     mpLastHit = pCandidate;
     return pCandidate;
 }
@@ -154,7 +144,12 @@ void CellAttributeHelper::doUnregister(const 
ScPatternAttr& rCandidate)
     if (mpLastHit == &rCandidate)
         mpLastHit = nullptr;
 
-    maRegisteredCellAttributes.erase(&rCandidate);
+    const OUString* pStyleName = rCandidate.GetStyleName();
+    auto it = maRegisteredCellAttributes.find(pStyleName ? 
std::optional<OUString>(*pStyleName) : std::nullopt);
+    assert(it != maRegisteredCellAttributes.end());
+    it->second.erase(&rCandidate);
+    if (it->second.empty())
+        maRegisteredCellAttributes.erase(it);
     delete &rCandidate;
 }
 
@@ -187,15 +182,13 @@ const ScPatternAttr& 
CellAttributeHelper::getDefaultCellAttribute() const
 void CellAttributeHelper::CellStyleDeleted(const ScStyleSheet& rStyle)
 {
     const OUString& rCandidateStyleName = rStyle.GetName();
-    auto it = maRegisteredCellAttributes.lower_bound(&rCandidateStyleName);
-    for (; it != maRegisteredCellAttributes.end(); ++it)
-    {
-        const ScPatternAttr* pCheck = *it;
-        if (CompareStringPtr(pCheck->GetStyleName(), &rCandidateStyleName) != 
0)
-            break;
-        if (&rStyle == pCheck->GetStyleSheet())
-            const_cast<ScPatternAttr*>(pCheck)->StyleToName();
-    }
+    auto it = maRegisteredCellAttributes.find(rCandidateStyleName);
+    if (it != maRegisteredCellAttributes.end())
+        for (const ScPatternAttr* pCheck : it->second)
+        {
+            if (&rStyle == pCheck->GetStyleSheet())
+                const_cast<ScPatternAttr*>(pCheck)->StyleToName();
+        }
 }
 
 void CellAttributeHelper::RenameCellStyle(ScStyleSheet& rStyle, const 
OUString& rNewName)
@@ -203,26 +196,32 @@ void CellAttributeHelper::RenameCellStyle(ScStyleSheet& 
rStyle, const OUString&
     std::vector<const ScPatternAttr*> aChanged;
 
     const OUString& rCandidateStyleName = rStyle.GetName();
-    auto it = maRegisteredCellAttributes.lower_bound(&rCandidateStyleName);
-    while(it != maRegisteredCellAttributes.end())
+    auto it = maRegisteredCellAttributes.find(rCandidateStyleName);
+    if (it != maRegisteredCellAttributes.end())
     {
-        const ScPatternAttr* pCheck = *it;
-        if (CompareStringPtr(pCheck->GetStyleName(), &rCandidateStyleName) != 
0)
-            break;
-        if (&rStyle == pCheck->GetStyleSheet())
+        for (auto it2 = it->second.begin(); it2 != it->second.end();)
         {
-            aChanged.push_back(pCheck);
-            // The name will change, we have to re-insert it
-            it = maRegisteredCellAttributes.erase(it);
+            const ScPatternAttr* pCheck = *it2;
+            if (&rStyle == pCheck->GetStyleSheet())
+            {
+                aChanged.push_back(pCheck);
+                // The name will change, we have to re-insert it
+                it2 = it->second.erase(it2);
+            }
+            else
+                ++it2;
         }
-        else
-            ++it;
+        if (it->second.empty())
+            maRegisteredCellAttributes.erase(it);
     }
 
     rStyle.SetName(rNewName);
 
     for (const ScPatternAttr* p : aChanged)
-        maRegisteredCellAttributes.insert(p);
+    {
+        const OUString* pStyleName = p->GetStyleName();
+        maRegisteredCellAttributes[pStyleName ? 
std::optional<OUString>(*pStyleName) : std::nullopt].insert(p);
+    }
 }
 
 void CellAttributeHelper::CellStyleCreated(ScDocument& rDoc, const OUString& 
rName)
@@ -232,12 +231,13 @@ void CellAttributeHelper::CellStyleCreated(ScDocument& 
rDoc, const OUString& rNa
     // Calling StyleSheetChanged isn't enough because the pool may still 
contain items
     // for undo or clipboard content.
     std::vector<const ScPatternAttr*> aChanged;
-    auto it = maRegisteredCellAttributes.lower_bound(&rName);
-    while(it != maRegisteredCellAttributes.end())
+    auto it = maRegisteredCellAttributes.find(rName);
+    if (it == maRegisteredCellAttributes.end())
+        return;
+
+    for (auto it2 = it->second.begin(); it2 != it->second.end();)
     {
-        const ScPatternAttr* pCheck = *it;
-        if (CompareStringPtr(pCheck->GetStyleName(), &rName) != 0)
-            break;
+        const ScPatternAttr* pCheck = *it2;
         // tdf#163831 Invalidate cache if the style is modified/created
         const_cast<ScPatternAttr*>(pCheck)->InvalidateCaches();
         if (nullptr == pCheck->GetStyleSheet())
@@ -245,22 +245,29 @@ void CellAttributeHelper::CellStyleCreated(ScDocument& 
rDoc, const OUString& rNa
             {
                 aChanged.push_back(pCheck);
                 // if the name changed, we have to re-insert it
-                it = maRegisteredCellAttributes.erase(it);
+                it2 = it->second.erase(it2);
             }
             else
-                ++it;
+                ++it2;
         else
-            ++it;
+            ++it2;
     }
+    if (it->second.empty())
+        maRegisteredCellAttributes.erase(it);
+
     for (const ScPatternAttr* p : aChanged)
-        maRegisteredCellAttributes.insert(p);
+    {
+        const OUString* pStyleName = p->GetStyleName();
+        maRegisteredCellAttributes[pStyleName ? 
std::optional<OUString>(*pStyleName) : std::nullopt].insert(p);
+    }
 }
 
 void CellAttributeHelper::UpdateAllStyleSheets(ScDocument& rDoc)
 {
     bool bNameChanged = false;
-    for (const ScPatternAttr* pCheck : maRegisteredCellAttributes)
-        bNameChanged |= 
const_cast<ScPatternAttr*>(pCheck)->UpdateStyleSheet(rDoc);
+    for (const auto & rPair : maRegisteredCellAttributes)
+        for (const ScPatternAttr* pCheck : rPair.second)
+            bNameChanged |= 
const_cast<ScPatternAttr*>(pCheck)->UpdateStyleSheet(rDoc);
     if (bNameChanged)
         ReIndexRegistered();
 
@@ -271,8 +278,9 @@ void CellAttributeHelper::UpdateAllStyleSheets(ScDocument& 
rDoc)
 
 void CellAttributeHelper::AllStylesToNames()
 {
-    for (const ScPatternAttr* pCheck : maRegisteredCellAttributes)
-        const_cast<ScPatternAttr*>(pCheck)->StyleToName();
+    for (const auto & rPair : maRegisteredCellAttributes)
+        for (const ScPatternAttr* pCheck : rPair.second)
+            const_cast<ScPatternAttr*>(pCheck)->StyleToName();
 
     // force existence, then access
     getDefaultCellAttribute();
@@ -282,38 +290,22 @@ void CellAttributeHelper::AllStylesToNames()
 /// If the style name changed, we need to reindex.
 void CellAttributeHelper::ReIndexRegistered()
 {
-    RegisteredAttrSet aNewSet;
-    for (auto const & p : maRegisteredCellAttributes)
-        aNewSet.insert(p);
-    maRegisteredCellAttributes = std::move(aNewSet);
-}
+    RegisteredAttrMap aNewMap;
+    for (const auto & rPair : maRegisteredCellAttributes)
+        for (const ScPatternAttr* p : rPair.second)
+        {
+            const OUString* pStyleName = p->GetStyleName();
+            aNewMap[pStyleName ? std::optional<OUString>(*pStyleName) : 
std::nullopt].insert(p);
+        }
 
-bool CellAttributeHelper::RegisteredAttrSetLess::operator()(const 
ScPatternAttr* lhs, const ScPatternAttr* rhs) const
-{
-    int cmp = CompareStringPtr(lhs->GetStyleName(), rhs->GetStyleName());
-    if (cmp < 0)
-        return true;
-    if (cmp > 0)
-        return false;
-    return lhs < rhs;
-}
-bool CellAttributeHelper::RegisteredAttrSetLess::operator()(const 
ScPatternAttr* lhs, const OUString* rhs) const
-{
-    int cmp = CompareStringPtr(lhs->GetStyleName(), rhs);
-    if (cmp < 0)
-        return true;
-    if (cmp > 0)
-        return false;
-    return false;
+    maRegisteredCellAttributes = std::move(aNewMap);
 }
-bool CellAttributeHelper::RegisteredAttrSetLess::operator()(const OUString* 
lhs, const ScPatternAttr* rhs) const
+
+size_t CellAttributeHelper::RegisteredAttrMapHash::operator()(const 
std::optional<OUString>& p) const
 {
-    int cmp = CompareStringPtr(lhs, rhs->GetStyleName());
-    if (cmp < 0)
-        return true;
-    if (cmp > 0)
-        return false;
-    return true;
+    if (!p)
+        return 0;
+    return p->hashCode();
 }
 
 

Reply via email to