svl/source/items/itemset.cxx |   29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

New commits:
commit aa85b303cde517e187a7c3404f9b63f0a0752bf3
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Fri Feb 18 11:54:37 2022 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Fri Feb 18 12:15:43 2022 +0100

    avoid an allocation in WhichRangesContainer::MergeRange
    
    speeds up loading a large chart by 5%
    
    Change-Id: Idd8566012a0049d429e38b589782fc6d76eb3a5a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130132
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/svl/source/items/itemset.cxx b/svl/source/items/itemset.cxx
index bfaf0a60e169..7953cd922363 100644
--- a/svl/source/items/itemset.cxx
+++ b/svl/source/items/itemset.cxx
@@ -1478,46 +1478,53 @@ WhichRangesContainer 
WhichRangesContainer::MergeRange(sal_uInt16 nFrom,
 
     // create vector of ranges (sal_uInt16 pairs of lower and upper bound)
     const size_t nOldCount = size();
-    std::vector<WhichPair> aRangesTable;
-    aRangesTable.reserve(nOldCount);
+    // Allocate one item more than we already have.
+    // In the worst case scenario we waste a little bit
+    // of memory, but we avoid another allocation, which is more important.
+    std::unique_ptr<WhichPair[]> aRangesTable(new WhichPair[nOldCount+1]);
+    int aRangesTableSize = 0;
     bool bAdded = false;
     for (const auto& rPair : *this)
     {
         if (!bAdded && rPair.first >= nFrom)
         { // insert new range, keep ranges sorted
-            aRangesTable.push_back({ nFrom, nTo });
+            aRangesTable[aRangesTableSize++] = { nFrom, nTo };
             bAdded = true;
         }
         // insert current range
-        aRangesTable.emplace_back(rPair);
+        aRangesTable[aRangesTableSize++] = rPair;
     }
     if (!bAdded)
-        aRangesTable.push_back({ nFrom, nTo });
+        aRangesTable[aRangesTableSize++] = { nFrom, nTo };
 
     // true if ranges overlap or adjoin, false if ranges are separate
     auto needMerge = [](WhichPair lhs, WhichPair rhs) {
         return (lhs.first - 1) <= rhs.second && (rhs.first - 1) <= lhs.second;
     };
 
-    auto it = aRangesTable.begin();
-    // we got at least one range
+    auto it = aRangesTable.get();
+    auto endIt = aRangesTable.get() + aRangesTableSize;
+    // we have at least one range at this point
     for (;;)
     {
         auto itNext = std::next(it);
-        if (itNext == aRangesTable.end())
+        if (itNext == endIt)
             break;
-        // check neighbouring ranges, find first range which overlaps or 
adjoins a previous range
+        // check if neighbouring ranges overlap or adjoin
         if (needMerge(*it, *itNext))
         {
             // lower bounds are sorted, implies: it->first = min(it[0].first, 
it[1].first)
             it->second = std::max(it->second, itNext->second);
-            aRangesTable.erase(itNext);
+            // remove next element
+            std::move(std::next(itNext), endIt, itNext);
+            --aRangesTableSize;
+            endIt = aRangesTable.get() + aRangesTableSize;
         }
         else
             ++it;
     }
 
-    return WhichRangesContainer(aRangesTable.data(), aRangesTable.size());
+    return WhichRangesContainer(std::move(aRangesTable), aRangesTableSize);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to