sw/inc/ndarr.hxx                 |    1 
 sw/inc/ndindex.hxx               |   40 ++++++++++++++++++++-------------------
 sw/inc/node.hxx                  |    2 +
 sw/source/core/docnode/nodes.cxx |   11 +++++-----
 4 files changed, 29 insertions(+), 25 deletions(-)

New commits:
commit 16c9053fe54b7c751b5c8c41ec7609199ebd6610
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Tue Aug 13 13:13:42 2024 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Thu Aug 15 18:49:12 2024 +0200

    tdf#158556 move m_vIndices to SwNode
    
    When we load complex documents we end up with very large
    amounts of SwNodeIndex objects, and we also need call
    RemoveNode often, which means we end up scanning tons of objects.
    
    So move the linked list from SwNodes to SwNode, so we can
    scan just the objects that we are interested in.
    
    Shaves 10% off the load time of a complex docx file.
    
    Change-Id: Id62388dbc7e41fae30acb7910a982710c80e563e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171888
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>
    Tested-by: Jenkins

diff --git a/sw/inc/ndarr.hxx b/sw/inc/ndarr.hxx
index 886384aca288..7bcebeda22db 100644
--- a/sw/inc/ndarr.hxx
+++ b/sw/inc/ndarr.hxx
@@ -95,7 +95,6 @@ class SwNodes final
     friend class SwStartNode;
     friend class ::sw::DocumentContentOperationsManager;
 
-    SwNodeIndex* m_vIndices; ///< ring of all indices on nodes.
     void RemoveNode( SwNodeOffset nDelPos, SwNodeOffset nLen, bool bDel );
 
     void InsertNode( SwNode* pNode, const SwNodeIndex& rPos );
diff --git a/sw/inc/ndindex.hxx b/sw/inc/ndindex.hxx
index 5ebc32846739..0f0cdabccee9 100644
--- a/sw/inc/ndindex.hxx
+++ b/sw/inc/ndindex.hxx
@@ -33,28 +33,26 @@ class SAL_WARN_UNUSED SW_DLLPUBLIC SwNodeIndex final : 
public sw::Ring<SwNodeInd
 
     void RegisterIndex()
     {
-        SwNodes& rNodes = GetNodes();
-        if(!rNodes.m_vIndices)
+        if(!m_pNode->m_vIndices)
         {
 #if defined(__GNUC__) && (__GNUC__ == 12 || __GNUC__ == 13)
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wdangling-pointer"
 #endif
-            rNodes.m_vIndices = this;
+            m_pNode->m_vIndices = this;
 #if defined(__GNUC__) && (__GNUC__ == 12 || __GNUC__ == 13)
 #pragma GCC diagnostic pop
 #endif
         }
-        MoveTo(rNodes.m_vIndices);
+        MoveTo(m_pNode->m_vIndices);
     }
     void DeRegisterIndex()
     {
-        SwNodes& rNodes = GetNodes();
-        if(rNodes.m_vIndices == this)
-            rNodes.m_vIndices = GetNextInRing();
+        if(m_pNode->m_vIndices == this)
+            m_pNode->m_vIndices = GetNextInRing();
         MoveTo(nullptr);
-        if(rNodes.m_vIndices == this)
-            rNodes.m_vIndices = nullptr;
+        if(m_pNode->m_vIndices == this)
+            m_pNode->m_vIndices = nullptr;
     }
 
     SwNodeIndex(SwNode* pNode) : m_pNode(pNode) { RegisterIndex(); }
@@ -155,31 +153,35 @@ public:
 
 inline SwNodeIndex& SwNodeIndex::operator=( SwNodeOffset const nNew )
 {
-    m_pNode = GetNodes()[ nNew ];
+    auto pNewNode = GetNodes()[ nNew ];
+    if (pNewNode != m_pNode)
+    {
+        DeRegisterIndex();
+        m_pNode = GetNodes()[ nNew ];
+        RegisterIndex();
+    }
     return *this;
 }
 
 SwNodeIndex& SwNodeIndex::operator=( const SwNode& rNd )
 {
-    if (&GetNodes() != &rNd.GetNodes())
+    if (&rNd != m_pNode)
     {
         DeRegisterIndex();
         m_pNode = const_cast<SwNode*>(&rNd);
         RegisterIndex();
     }
-    else
-        m_pNode = const_cast<SwNode*>(&rNd);
     return *this;
 }
 
 SwNodeIndex& SwNodeIndex::Assign( const SwNode& rNd, SwNodeOffset nOffset )
 {
-    *this = rNd;
-
-    if( nOffset )
-        m_pNode = GetNodes()[ GetIndex() + nOffset ];
-
-    return *this;
+    const SwNode* pNewNode;
+    if (nOffset)
+        pNewNode = rNd.GetNodes()[ rNd.GetIndex() + nOffset ];
+    else
+        pNewNode = &rNd;
+    return operator=(*pNewNode);
 }
 
 #endif
diff --git a/sw/inc/node.hxx b/sw/inc/node.hxx
index 5e968000cccf..d8eaeaa9058a 100644
--- a/sw/inc/node.hxx
+++ b/sw/inc/node.hxx
@@ -97,6 +97,7 @@ class SW_DLLPUBLIC SwNode
     : public sw::BorderCacheOwner, private BigPtrEntry
 {
     friend class SwNodes;
+    friend class SwNodeIndex;
 
     SwNodeType m_nNodeType;
 
@@ -105,6 +106,7 @@ class SW_DLLPUBLIC SwNode
     bool m_bIgnoreDontExpand : 1;     ///< for Text Attributes - ignore the 
flag
 
     mutable sw::AccessibilityCheckStatus m_aAccessibilityCheckStatus;
+    SwNodeIndex* m_vIndices { nullptr }; ///< ring of indices pointing to this 
node.
 
 public:
     /// sw_redlinehide: redline node merge state
diff --git a/sw/source/core/docnode/nodes.cxx b/sw/source/core/docnode/nodes.cxx
index 46f4a4aa8f46..e11ee0ce49d8 100644
--- a/sw/source/core/docnode/nodes.cxx
+++ b/sw/source/core/docnode/nodes.cxx
@@ -60,7 +60,7 @@ static sal_uInt16 HighestLevel( SwNodes & rNodes, const 
SwNodeRange & rRange );
  * @param rDocument TODO: provide documentation
  */
 SwNodes::SwNodes( SwDoc& rDocument )
-    : m_vIndices(nullptr), m_rMyDoc( rDocument )
+    : m_rMyDoc( rDocument )
 {
     m_bInNodesDel = m_bInDelUpdOutline = false;
 
@@ -2390,11 +2390,12 @@ void SwNodes::RemoveNode( SwNodeOffset nDelPos, 
SwNodeOffset nSz, bool bDel )
     SwNodeOffset nEnd = nDelPos + nSz;
     SwNode* pNew = (*this)[ nEnd ];
 
-    for (SwNodeIndex& rIndex : m_vIndices->GetRingContainer())
+    for (SwNodeOffset nCnt(0); nCnt < nSz; nCnt++)
     {
-        SwNodeOffset const nIdx = rIndex.GetIndex();
-        if (nDelPos <= nIdx && nIdx < nEnd)
-            rIndex = *pNew;
+        SwNode* pNode = (*this)[ nDelPos + nCnt ];
+        // the assignment will de-link the entry from the ring
+        while (pNode->m_vIndices)
+            (*pNode->m_vIndices) = *pNew;
     }
 
     std::vector<BigPtrEntry> aTempEntries;

Reply via email to