tdf#158556 speed up SwNodes::RemoveNode

Change-Id: I49daf93793c67da6261081fce92e1fed1a71248b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165139
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/sw/inc/bparr.hxx b/sw/inc/bparr.hxx
index 9f3e17f..4f831c8 100644
--- a/sw/inc/bparr.hxx
+++ b/sw/inc/bparr.hxx
@@ -91,6 +91,11 @@ public:
    void Move( sal_Int32 from, sal_Int32 to );
    void Replace( sal_Int32 pos, BigPtrEntry* p);

    /** Speed up the complicated removal logic in SwNodes::RemoveNode.
        Returns the entry before pNotTheOne.
    */
    BigPtrEntry* ReplaceTheOneAfter( BigPtrEntry* pNotTheOne, BigPtrEntry* pNewEntry);

    SW_DLLPUBLIC BigPtrEntry* operator[]( sal_Int32 ) const;
};

diff --git a/sw/source/core/bastyp/bparr.cxx b/sw/source/core/bastyp/bparr.cxx
index b99385b..03e035c 100644
--- a/sw/source/core/bastyp/bparr.cxx
+++ b/sw/source/core/bastyp/bparr.cxx
@@ -397,6 +397,47 @@ void BigPtrArray::Replace( sal_Int32 idx, BigPtrEntry* pElem)
    p->mvData[ idx - p->nStart ] = pElem;
}

/** Speed up the complicated removal logic in SwNodes::RemoveNode.
    Replaces the node AFTER pNotTheOne.
    Returns the entry BEFORE pNotTheOne.
*/
BigPtrEntry* BigPtrArray::ReplaceTheOneAfter( BigPtrEntry* pNotTheOne, BigPtrEntry* pNewEntry)
{
    assert(pNotTheOne->m_pBlock->pBigArr == this);
    BlockInfo* p = pNotTheOne->m_pBlock;
    sal_uInt16 nOffset = pNotTheOne->m_nOffset;

    // if the next node is inside the current block
    if (nOffset < p->nElem - 1)
    {
        ++nOffset;
        p->mvData[nOffset] = pNewEntry;
        pNewEntry->m_nOffset = nOffset;
        pNewEntry->m_pBlock = p;
        --nOffset;
    }
    else
    {
        // slow path
        BigPtrArray::Replace( pNotTheOne->GetPos()+1, pNewEntry );
    }

    // if the previous node is inside the current block
    if (nOffset != 0)
    {
        --nOffset;
        return p->mvData[nOffset];
    }
    else
    {
        // slow path
        sal_Int32 nPrevPos = pNotTheOne->GetPos();
        if (nPrevPos == 0)
            return nullptr;
        return BigPtrArray::operator[]( nPrevPos - 1 );
    }
}

/** Compress the array */
sal_uInt16 BigPtrArray::Compress()
{
diff --git a/sw/source/core/docnode/nodes.cxx b/sw/source/core/docnode/nodes.cxx
index 0e2a0bc..5f059f9 100644
--- a/sw/source/core/docnode/nodes.cxx
+++ b/sw/source/core/docnode/nodes.cxx
@@ -2413,14 +2413,8 @@ void SwNodes::RemoveNode( SwNodeOffset nDelPos, SwNodeOffset nSz, bool bDel )
            delete pDel;
            // coverity[use_after_free : FALSE] - pPrev will be reassigned if there will be another iteration to the loop
            pDel = pPrev;
            sal_uLong nPrevNdIdx = pPrev->GetPos();
            BigPtrEntry* pTempEntry = &aTempEntries[sal_Int32(nCnt)];
            BigPtrArray::Replace( nPrevNdIdx+1, pTempEntry );
            if( nCnt )
                pPrev = BigPtrArray::operator []( nPrevNdIdx  - 1 );
                    // the accessed element can be a naked BigPtrEntry from
                    // aTempEntries, so the downcast to SwNode* in
                    // SwNodes::operator[] would be illegal (and unnecessary)
            pPrev = ReplaceTheOneAfter(pPrev, pTempEntry);
        }
        nDelPos = SwNodeOffset(pDel->GetPos() + 1);
    }