sc/source/filter/excel/xetable.cxx |   38 +++++++++++++++++--------------------
 sc/source/filter/inc/xerecord.hxx  |   15 ++++++++++++++
 2 files changed, 33 insertions(+), 20 deletions(-)

New commits:
commit 58c6a36bfcc853ca9da81fbc2d071fa50585655b
Author:     Luboš Luňák <[email protected]>
AuthorDate: Mon Mar 7 12:48:37 2022 +0100
Commit:     Luboš Luňák <[email protected]>
CommitDate: Mon Mar 7 15:37:00 2022 +0100

    optimize repeated std::vector removal (tdf#126326)
    
    Also it's enough to use just pointers to the elements, no need
    to refcount.
    
    Change-Id: I2e6a2f981d75e3dd57aefb41ba1fdbf800fed813
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131107
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <[email protected]>

diff --git a/sc/source/filter/excel/xetable.cxx 
b/sc/source/filter/excel/xetable.cxx
index c527d525adba..f9cfc64d4deb 100644
--- a/sc/source/filter/excel/xetable.cxx
+++ b/sc/source/filter/excel/xetable.cxx
@@ -1753,31 +1753,31 @@ void XclExpColinfoBuffer::Finalize( ScfUInt16Vec& 
rXFIndexes, bool bXLS )
     rXFIndexes.clear();
     rXFIndexes.reserve( maColInfos.GetSize() );
 
-    size_t nPos, nSize;
-
-    // do not cache the record list size, it may change in the loop
-    for( nPos = 0; nPos < maColInfos.GetSize(); ++nPos )
+    if( !maColInfos.IsEmpty())
     {
-        XclExpColinfoRef xRec = maColInfos.GetRecord( nPos );
-        xRec->ConvertXFIndexes();
-
-        // try to merge with previous record
-        if( nPos > 0 )
+        XclExpColinfo* xPrevRec = maColInfos.GetRecord( 0 );
+        xPrevRec->ConvertXFIndexes();
+        for( size_t nPos = 1; nPos < maColInfos.GetSize(); ++nPos )
         {
-            XclExpColinfoRef xPrevRec = maColInfos.GetRecord( nPos - 1 );
+            XclExpColinfo* xRec = maColInfos.GetRecord( nPos );
+            xRec->ConvertXFIndexes();
+
+            // try to merge with previous record
             if( xPrevRec->TryMerge( *xRec ) )
-                // adjust nPos to get the next COLINFO record at the same 
position
-                maColInfos.RemoveRecord( nPos-- );
+                maColInfos.InvalidateRecord( nPos );
+            else
+                xPrevRec = xRec;
         }
+        maColInfos.RemoveInvalidatedRecords();
     }
 
     // put XF indexes into passed vector, collect use count of all different 
widths
     std::unordered_map< sal_uInt16, sal_uInt16 > aWidthMap;
     sal_uInt16 nMaxColCount = 0;
     sal_uInt16 nMaxUsedWidth = 0;
-    for( nPos = 0, nSize = maColInfos.GetSize(); nPos < nSize; ++nPos )
+    for( size_t nPos = 0; nPos < maColInfos.GetSize(); ++nPos )
     {
-        XclExpColinfoRef xRec = maColInfos.GetRecord( nPos );
+        const XclExpColinfo* xRec = maColInfos.GetRecord( nPos );
         sal_uInt16 nColCount = xRec->GetColCount();
 
         // add XF index to passed vector
@@ -1796,15 +1796,13 @@ void XclExpColinfoBuffer::Finalize( ScfUInt16Vec& 
rXFIndexes, bool bXLS )
     maDefcolwidth.SetDefWidth( nMaxUsedWidth, bXLS );
 
     // remove all default COLINFO records
-    nPos = 0;
-    while( nPos < maColInfos.GetSize() )
+    for( size_t nPos = 0; nPos < maColInfos.GetSize(); ++nPos )
     {
-        XclExpColinfoRef xRec = maColInfos.GetRecord( nPos );
+        XclExpColinfo* xRec = maColInfos.GetRecord( nPos );
         if( xRec->IsDefault( maDefcolwidth ) )
-            maColInfos.RemoveRecord( nPos );
-        else
-            ++nPos;
+            maColInfos.InvalidateRecord( nPos );
     }
+    maColInfos.RemoveInvalidatedRecords();
 }
 
 void XclExpColinfoBuffer::Save( XclExpStream& rStrm )
diff --git a/sc/source/filter/inc/xerecord.hxx 
b/sc/source/filter/inc/xerecord.hxx
index 4c37f1b6e7a5..c6901e7fb022 100644
--- a/sc/source/filter/inc/xerecord.hxx
+++ b/sc/source/filter/inc/xerecord.hxx
@@ -24,6 +24,7 @@
 #include "xlstream.hxx"
 #include <salhelper/simplereferenceobject.hxx>
 #include <rtl/ref.hxx>
+#include <algorithm>
 
 // Base classes to export Excel records =======================================
 
@@ -385,6 +386,20 @@ public:
             (*aIt)->SaveXml( rStrm );
     }
 
+    /**
+     Optimization for repeated removal. Since this is internally a vector, 
repeated RemoveRecord()
+     would repeatedly move all items after the removed position. Instead it's 
possible to invalidate
+     a record and then call RemoveInvalidatedRecords() at the end (which is 
necessary, the list is generally
+     not allowed to contain invalid entries).
+    */
+    void        InvalidateRecord( size_t nPos ) { maRecs[ nPos ] = nullptr; }
+    void        RemoveInvalidatedRecords()
+    {
+        maRecs.erase(
+            std::remove_if( maRecs.begin(), maRecs.end(), [](const 
RecordRefType& xRec) { return xRec == nullptr; } ),
+            maRecs.end());
+    }
+
 private:
     typedef ::std::vector< RecordRefType > RecordVec;
     RecordVec           maRecs;

Reply via email to