sw/inc/IDocumentMarkAccess.hxx       |    7 ++
 sw/source/core/doc/CntntIdxStore.cxx |    4 +
 sw/source/core/doc/docbm.cxx         |   84 +++++++++++++++++++++++++++++++++--
 sw/source/core/inc/MarkManager.hxx   |    1 
 4 files changed, 92 insertions(+), 4 deletions(-)

New commits:
commit 62de2163967c8a55193f126922dc21261644784d
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Sat Aug 10 15:18:15 2024 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Sun Aug 11 08:51:50 2024 +0200

    speedup sorting of marks in markmanager
    
    when we modify them in ContentIdxStoreImpl, we typically only modify a
    tiny subset of the marks, so do a partial sort instead of fully sorting
    the array. Shaves 10% off the load time of a large docx with lots of
    fieldmarks and bookmarks
    
    Change-Id: Ia271e465fb71559b0d4da3242dc4a6e6f07ddc28
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171716
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/sw/inc/IDocumentMarkAccess.hxx b/sw/inc/IDocumentMarkAccess.hxx
index e7c98e7a18c2..1f838c9730e0 100644
--- a/sw/inc/IDocumentMarkAccess.hxx
+++ b/sw/inc/IDocumentMarkAccess.hxx
@@ -207,6 +207,13 @@ class IDocumentMarkAccess
 
         virtual void assureSortedMarkContainers() const = 0;
 
+        /**
+         * called when we need to sort a sub-range of the container, elements 
starting
+         * at nMinIndexModified where modified. This is used from 
ContentIdxStoreImpl::RestoreBkmks,
+         * where we are only modifying a small range at the end of the 
container.
+         */
+        virtual void assureSortedMarkContainers(sal_Int32 nMinIndexModified) 
const = 0;
+
         /** returns a STL-like random access iterator to the begin of the 
sequence of marks.
         */
         virtual const_iterator getAllMarksBegin() const =0;
diff --git a/sw/source/core/doc/CntntIdxStore.cxx 
b/sw/source/core/doc/CntntIdxStore.cxx
index 03ee3de02f18..5ef370dbe98b 100644
--- a/sw/source/core/doc/CntntIdxStore.cxx
+++ b/sw/source/core/doc/CntntIdxStore.cxx
@@ -258,10 +258,12 @@ void ContentIdxStoreImpl::SaveBkmks(SwDoc& rDoc, 
SwNodeOffset nNode, sal_Int32 n
 void ContentIdxStoreImpl::RestoreBkmks(SwDoc& rDoc, updater_t const & rUpdater)
 {
     IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess();
+    sal_Int32 nMinIndexModified = SAL_MAX_INT32;
     for (const MarkEntry& aEntry : m_aBkmkEntries)
     {
         if (MarkBase *const pMark = 
pMarkAccess->getAllMarksBegin()[aEntry.m_nIdx])
         {
+            nMinIndexModified = std::min(nMinIndexModified, 
sal_Int32(aEntry.m_nIdx));
             SwPosition aNewPos(GetRightMarkPos(pMark, aEntry.m_bOther));
             rUpdater(aNewPos, aEntry.m_nContent);
             SetRightMarkPos(pMark, aEntry.m_bOther, &aNewPos);
@@ -270,7 +272,7 @@ void ContentIdxStoreImpl::RestoreBkmks(SwDoc& rDoc, 
updater_t const & rUpdater)
     if (!m_aBkmkEntries.empty())
     {   // tdf#105705 sort bookmarks because SaveBkmks special handling of
         // "bMarkPosEqual" may destroy sort order
-        pMarkAccess->assureSortedMarkContainers();
+        pMarkAccess->assureSortedMarkContainers(nMinIndexModified);
     }
 }
 
diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx
index 500c81fa0be6..40cde87499fa 100644
--- a/sw/source/core/doc/docbm.cxx
+++ b/sw/source/core/doc/docbm.cxx
@@ -1801,6 +1801,12 @@ namespace sw::mark
         const_cast< MarkManager* >(this)->sortMarks();
     }
 
+    void MarkManager::sortMarks()
+    {
+        sort(m_vAllMarks.begin(), m_vAllMarks.end(), 
&lcl_MarkOrderingByStart<MarkBase>);
+        sortSubsetMarks();
+    }
+
     void MarkManager::sortSubsetMarks()
     {
         stable_sort(m_vBookmarks.begin(), m_vBookmarks.end(), 
&lcl_MarkOrderingByStart<MarkBase>);
@@ -1808,10 +1814,82 @@ namespace sw::mark
         sort(m_vAnnotationMarks.begin(), m_vAnnotationMarks.end(), 
&lcl_MarkOrderingByStart<MarkBase>);
     }
 
-    void MarkManager::sortMarks()
+    template<class MarkT>
+    static void lcl_assureSortedMarkContainers(typename std::vector<MarkT*>& 
rContainer,
+                    sal_Int32 nMinIndexModified)
     {
-        sort(m_vAllMarks.begin(), m_vAllMarks.end(), 
&lcl_MarkOrderingByStart<MarkBase>);
-        sortSubsetMarks();
+        // We know that the range nMinIndexModified.. has been modified, now 
we need to extend that range
+        // to find the total range of elements that need to be sorted.
+        // We know that the marks have been modified in fairly limited ways, 
see ContentIdxStoreImpl.
+        sal_Int32 nMin = nMinIndexModified;
+        while (nMin != 0)
+        {
+            nMin--;
+            if (rContainer[nMin]->GetMarkStart() < 
rContainer[nMinIndexModified]->GetMarkStart())
+                break;
+        }
+        sort(rContainer.begin() + nMin, rContainer.end(), 
&lcl_MarkOrderingByStart<MarkT>);
+    }
+
+    template<class MarkT>
+    static void lcl_assureSortedMarkSubContainers(typename 
std::vector<MarkT*>& rContainer,
+                    MarkT* pFound)
+    {
+        if (pFound)
+        {
+            auto it = std::find(rContainer.rbegin(), rContainer.rend(), 
pFound);
+            sal_Int32 nFirstModified = std::distance(rContainer.begin(), 
(it+1).base());
+            lcl_assureSortedMarkContainers<MarkT>(rContainer, nFirstModified);
+        }
+    }
+
+    /**
+     * called when we need to sort a sub-range of the container, elements 
starting
+     * at nMinIndexModified were modified. This is used from 
ContentIdxStoreImpl::RestoreBkmks,
+     * where we are only modifying a small range at the end of the container.
+     */
+    void MarkManager::assureSortedMarkContainers(sal_Int32 nMinIndexModified) 
const
+    {
+        // check if the modified range contains elements from the other sorted 
containers
+        Bookmark* pBookmark = nullptr;
+        Fieldmark* pFieldmark = nullptr;
+        AnnotationMark* pAnnotationMark = nullptr;
+        for (auto it = m_vAllMarks.begin() + nMinIndexModified; it != 
m_vAllMarks.end(); ++it)
+        {
+            switch(IDocumentMarkAccess::GetType(**it))
+            {
+                case IDocumentMarkAccess::MarkType::BOOKMARK:
+                case IDocumentMarkAccess::MarkType::CROSSREF_HEADING_BOOKMARK:
+                case IDocumentMarkAccess::MarkType::CROSSREF_NUMITEM_BOOKMARK:
+                    if (!pBookmark)
+                        pBookmark = static_cast<Bookmark*>(*it);
+                    break;
+                case IDocumentMarkAccess::MarkType::TEXT_FIELDMARK:
+                case IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK:
+                case IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK:
+                case IDocumentMarkAccess::MarkType::DATE_FIELDMARK:
+                    if (!pFieldmark)
+                        pFieldmark = static_cast<Fieldmark*>(*it);
+                    break;
+
+                case IDocumentMarkAccess::MarkType::ANNOTATIONMARK:
+                    if (!pAnnotationMark)
+                        pAnnotationMark = static_cast<AnnotationMark*>(*it);
+                    break;
+
+                case IDocumentMarkAccess::MarkType::DDE_BOOKMARK:
+                case IDocumentMarkAccess::MarkType::NAVIGATOR_REMINDER:
+                case IDocumentMarkAccess::MarkType::UNO_BOOKMARK:
+                    // no special marks container
+                    break;
+            }
+        }
+
+        auto pThis = const_cast<MarkManager*>(this);
+        lcl_assureSortedMarkContainers<MarkBase>(pThis->m_vAllMarks, 
nMinIndexModified);
+        lcl_assureSortedMarkSubContainers<Bookmark>(pThis->m_vBookmarks, 
pBookmark);
+        lcl_assureSortedMarkSubContainers<Fieldmark>(pThis->m_vFieldmarks, 
pFieldmark);
+        
lcl_assureSortedMarkSubContainers<AnnotationMark>(pThis->m_vAnnotationMarks, 
pAnnotationMark);
     }
 
 template<class MarkT>
diff --git a/sw/source/core/inc/MarkManager.hxx 
b/sw/source/core/inc/MarkManager.hxx
index 0b2d8850a201..18886256ba98 100644
--- a/sw/source/core/inc/MarkManager.hxx
+++ b/sw/source/core/inc/MarkManager.hxx
@@ -123,6 +123,7 @@ namespace sw::mark {
             virtual std::vector<sw::mark::AnnotationMark*>::const_iterator 
findFirstAnnotationStartsAfter(const SwPosition& rPos) const override;
 
             virtual void assureSortedMarkContainers() const override;
+            virtual void assureSortedMarkContainers(sal_Int32 
nMinIndexModified) const override;
 
             typedef std::vector<sw::mark::MarkBase*> container_t;
 

Reply via email to