tdf#120445 File-open ODS: Slower as compared to LibO 4.4.7.2
This takes opening the file from 21s to 9.4s on my machine
Change-Id: I38248f3c9acfa413fc105fcbe9ece06192389d46
Reviewed-on: https://gerrit.libreoffice.org/70073
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/sc/inc/markarr.hxx b/sc/inc/markarr.hxx
index 4b538d9..d30168d 100644
--- a/sc/inc/markarr.hxx
+++ b/sc/inc/markarr.hxx
@@ -43,17 +43,19 @@
public:
ScMarkArray();
ScMarkArray( ScMarkArray&& rArray );
ScMarkArray( const ScMarkArray& rArray );
~ScMarkArray();
void Reset( bool bMarked = false, SCSIZE nNeeded = 1 );
bool GetMark( SCROW nRow ) const;
void SetMarkArea( SCROW nStartRow, SCROW nEndRow, bool bMarked );
bool IsAllMarked( SCROW nStartRow, SCROW nEndRow ) const;
bool HasOneMark( SCROW& rStartRow, SCROW& rEndRow ) const;
bool HasEqualRowsMarked( const ScMarkArray& rOther ) const;
bool HasMarks() const { return ( nCount > 1 || ( nCount == 1 && pData[0].bMarked ) ); }
void CopyMarksTo( ScMarkArray& rDestMarkArray ) const;
ScMarkArray& operator=( ScMarkArray const & rSource );
ScMarkArray& operator=( ScMarkArray&& rSource );
bool operator==(ScMarkArray const & rOther ) const;
bool Search( SCROW nRow, SCSIZE& nIndex ) const;
diff --git a/sc/inc/markmulti.hxx b/sc/inc/markmulti.hxx
index ee92da3..dc0f0b2 100644
--- a/sc/inc/markmulti.hxx
+++ b/sc/inc/markmulti.hxx
@@ -23,13 +23,13 @@
#include "segmenttree.hxx"
#include "markarr.hxx"
#include <map>
#include <vector>
class ScMultiSel
{
private:
typedef std::map<SCCOL, ScMarkArray> MapType;
typedef std::vector<ScMarkArray> MapType;
MapType aMultiSelContainer;
ScMarkArray aRowSel;
@@ -43,11 +43,7 @@
ScMultiSel& operator=(const ScMultiSel& rMultiSel);
ScMultiSel& operator=(const ScMultiSel&& rMultiSel) = delete;
SCCOL size() const
{
return static_cast<SCCOL>( aMultiSelContainer.size() );
}
SCCOL GetMultiSelectionCount() const;
bool HasMarks( SCCOL nCol ) const;
bool HasOneMark( SCCOL nCol, SCROW& rStartRow, SCROW& rEndRow ) const;
bool GetMark( SCCOL nCol, SCROW nRow ) const;
diff --git a/sc/qa/unit/mark_test.cxx b/sc/qa/unit/mark_test.cxx
index f8d041c..ad6124c 100644
--- a/sc/qa/unit/mark_test.cxx
+++ b/sc/qa/unit/mark_test.cxx
@@ -243,7 +243,7 @@
ScMarkData aMark;
ScMultiSel aMultiSel;
CPPUNIT_ASSERT( !aMark.IsMarked() && !aMark.IsMultiMarked() );
CPPUNIT_ASSERT_EQUAL( SCCOL(0), aMultiSel.size() );
CPPUNIT_ASSERT_EQUAL( SCCOL(0), aMultiSel.GetMultiSelectionCount() );
CPPUNIT_ASSERT( !aMultiSel.HasAnyMarks() );
for ( const auto& rAreaTestData : rMarksData.aMarks )
@@ -392,7 +392,7 @@
CPPUNIT_ASSERT( !aMultiSel.HasEqualRowsMarked( rColsWithUnequalMarks.first, rColsWithUnequalMarks.second ) );
aMultiSel.Clear();
CPPUNIT_ASSERT_EQUAL( SCCOL(0), aMultiSel.size() );
CPPUNIT_ASSERT_EQUAL( SCCOL(0), aMultiSel.GetMultiSelectionCount() );
CPPUNIT_ASSERT( !aMultiSel.HasAnyMarks() );
}
diff --git a/sc/source/core/data/markarr.cxx b/sc/source/core/data/markarr.cxx
index 727b563..c981c98 100644
--- a/sc/source/core/data/markarr.cxx
+++ b/sc/source/core/data/markarr.cxx
@@ -31,13 +31,15 @@
}
// Move constructor
ScMarkArray::ScMarkArray( ScMarkArray&& rArray ) :
nCount( rArray.nCount ),
nLimit( rArray.nLimit ),
pData( rArray.pData.release() )
ScMarkArray::ScMarkArray( ScMarkArray&& rOther )
{
rArray.nCount = 0;
rArray.nLimit = 0;
operator=(std::move(rOther));
}
// Copy constructor
ScMarkArray::ScMarkArray( const ScMarkArray & rOther )
{
operator=(rOther);
}
ScMarkArray::~ScMarkArray()
@@ -293,7 +295,7 @@
return bRet;
}
bool ScMarkArray::HasEqualRowsMarked( const ScMarkArray& rOther ) const
bool ScMarkArray::operator==( const ScMarkArray& rOther ) const
{
if (nCount != rOther.nCount)
return false;
@@ -308,17 +310,28 @@
return true;
}
void ScMarkArray::CopyMarksTo( ScMarkArray& rDestMarkArray ) const
ScMarkArray& ScMarkArray::operator=( const ScMarkArray& rOther )
{
if (pData)
if (rOther.pData)
{
rDestMarkArray.pData.reset( new ScMarkEntry[nCount] );
memcpy( rDestMarkArray.pData.get(), pData.get(), nCount * sizeof(ScMarkEntry) );
pData.reset( new ScMarkEntry[rOther.nCount] );
memcpy( pData.get(), rOther.pData.get(), rOther.nCount * sizeof(ScMarkEntry) );
}
else
rDestMarkArray.pData.reset();
pData.reset();
rDestMarkArray.nCount = rDestMarkArray.nLimit = nCount;
nCount = nLimit = rOther.nCount;
return *this;
}
ScMarkArray& ScMarkArray::operator=( ScMarkArray&& rOther )
{
nCount = rOther.nCount;
nLimit = rOther.nLimit;
pData = std::move( rOther.pData );
rOther.nCount = 0;
rOther.nLimit = 0;
return *this;
}
SCROW ScMarkArray::GetNextMarked( SCROW nRow, bool bUp ) const
diff --git a/sc/source/core/data/markmulti.cxx b/sc/source/core/data/markmulti.cxx
index 8dc8ab3..61a77ac 100644
--- a/sc/source/core/data/markmulti.cxx
+++ b/sc/source/core/data/markmulti.cxx
@@ -23,43 +23,24 @@
#include <algorithm>
ScMultiSel::ScMultiSel():
aMultiSelContainer(),
aRowSel()
ScMultiSel::ScMultiSel()
{
}
ScMultiSel::ScMultiSel( const ScMultiSel& rMultiSel )
ScMultiSel::ScMultiSel( const ScMultiSel& rOther )
{
MapType::iterator aDestEnd = aMultiSelContainer.end();
MapType::iterator aDestIter = aDestEnd;
for ( const auto& aSourcePair : rMultiSel.aMultiSelContainer )
{
// correct hint is always aDestEnd as keys come in ascending order
// Amortized constant time operation as we always give the correct hint
aDestIter = aMultiSelContainer.emplace_hint( aDestEnd, aSourcePair.first, ScMarkArray() );
aSourcePair.second.CopyMarksTo( aDestIter->second );
}
rMultiSel.aRowSel.CopyMarksTo( aRowSel );
aRowSel = rOther.aRowSel;
aMultiSelContainer = rOther.aMultiSelContainer;
}
ScMultiSel::~ScMultiSel()
{
}
ScMultiSel& ScMultiSel::operator=(const ScMultiSel& rMultiSel)
ScMultiSel& ScMultiSel::operator=(const ScMultiSel& rOther)
{
Clear();
MapType::iterator aDestEnd = aMultiSelContainer.end();
MapType::iterator aDestIter = aDestEnd;
for ( const auto& aSourcePair : rMultiSel.aMultiSelContainer )
{
// correct hint is always aDestEnd as keys come in ascending order
// Amortized constant time operation as we always give the correct hint
aDestIter = aMultiSelContainer.emplace_hint( aDestEnd, aSourcePair.first, ScMarkArray() );
aSourcePair.second.CopyMarksTo( aDestIter->second );
}
rMultiSel.aRowSel.CopyMarksTo( aRowSel );
aRowSel = rOther.aRowSel;
aMultiSelContainer = rOther.aMultiSelContainer;
return *this;
}
@@ -69,24 +50,28 @@
aRowSel.Reset();
}
SCCOL ScMultiSel::GetMultiSelectionCount() const
{
SCCOL nCount = 0;
for (const auto & i : aMultiSelContainer)
if (i.HasMarks())
++nCount;
return nCount;
}
bool ScMultiSel::HasMarks( SCCOL nCol ) const
{
if ( aRowSel.HasMarks() )
return true;
MapType::const_iterator aIter = aMultiSelContainer.find( nCol );
if ( aIter == aMultiSelContainer.end() )
return false;
return aIter->second.HasMarks();
return nCol < static_cast<SCCOL>(aMultiSelContainer.size()) && aMultiSelContainer[nCol].HasMarks();
}
bool ScMultiSel::HasOneMark( SCCOL nCol, SCROW& rStartRow, SCROW& rEndRow ) const
{
bool aResult2 = false;
SCROW nRow1 = -1, nRow2 = -1, nRow3 = -1, nRow4 = -1;
bool aResult1 = aRowSel.HasOneMark( nRow1, nRow2 );
MapType::const_iterator aIter = aMultiSelContainer.find( nCol );
if ( aIter != aMultiSelContainer.end() )
aResult2 = aIter->second.HasOneMark( nRow3, nRow4 );
bool aResult2 = nCol < static_cast<SCCOL>(aMultiSelContainer.size())
&& aMultiSelContainer[nCol].HasOneMark( nRow3, nRow4 );
if ( aResult1 || aResult2 )
{
@@ -121,17 +106,13 @@
{
if ( aRowSel.GetMark( nRow ) )
return true;
MapType::const_iterator aIter = aMultiSelContainer.find( nCol );
if ( aIter != aMultiSelContainer.end() )
return aIter->second.GetMark( nRow );
return false;
return nCol < static_cast<SCCOL>(aMultiSelContainer.size()) && aMultiSelContainer[nCol].GetMark(nRow);
}
bool ScMultiSel::IsAllMarked( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const
{
bool bHasMarks1 = aRowSel.HasMarks();
MapType::const_iterator aIter = aMultiSelContainer.find( nCol );
bool bHasMarks2 = ( aIter != aMultiSelContainer.end() && aIter->second.HasMarks() );
bool bHasMarks2 = nCol < static_cast<SCCOL>(aMultiSelContainer.size()) && aMultiSelContainer[nCol].HasMarks();
if ( !bHasMarks1 && !bHasMarks2 )
return false;
@@ -139,7 +120,7 @@
if ( bHasMarks1 && bHasMarks2 )
{
if ( aRowSel.IsAllMarked( nStartRow, nEndRow ) ||
aIter->second.IsAllMarked( nStartRow, nEndRow ) )
aMultiSelContainer[nCol].IsAllMarked( nStartRow, nEndRow ) )
return true;
ScMultiSelIter aMultiIter( *this, nCol );
ScFlatBoolRowSegments::RangeData aRowRange;
@@ -150,24 +131,21 @@
if ( bHasMarks1 )
return aRowSel.IsAllMarked( nStartRow, nEndRow );
return aIter->second.IsAllMarked( nStartRow, nEndRow );
return aMultiSelContainer[nCol].IsAllMarked( nStartRow, nEndRow );
}
bool ScMultiSel::HasEqualRowsMarked( SCCOL nCol1, SCCOL nCol2 ) const
{
MapType::const_iterator aIter1 = aMultiSelContainer.find( nCol1 );
MapType::const_iterator aIter2 = aMultiSelContainer.find( nCol2 );
MapType::const_iterator aEnd = aMultiSelContainer.end();
bool bCol1Exists = ( aIter1 != aEnd );
bool bCol2Exists = ( aIter2 != aEnd );
bool bCol1Exists = nCol1 < static_cast<SCCOL>(aMultiSelContainer.size());
bool bCol2Exists = nCol2 < static_cast<SCCOL>(aMultiSelContainer.size());
if ( bCol1Exists || bCol2Exists )
{
if ( bCol1Exists && bCol2Exists )
return aIter1->second.HasEqualRowsMarked( aIter2->second );
return aMultiSelContainer[nCol1] == aMultiSelContainer[nCol2];
else if ( bCol1Exists )
return !aIter1->second.HasMarks();
return !aMultiSelContainer[nCol1].HasMarks();
else
return !aIter2->second.HasMarks();
return !aMultiSelContainer[nCol2].HasMarks();
}
return true;
@@ -175,13 +153,12 @@
SCROW ScMultiSel::GetNextMarked( SCCOL nCol, SCROW nRow, bool bUp ) const
{
MapType::const_iterator aIter = aMultiSelContainer.find( nCol );
if ( aIter == aMultiSelContainer.end() )
if ( nCol >= static_cast<SCCOL>(aMultiSelContainer.size()) || !aMultiSelContainer[nCol].HasMarks() )
return aRowSel.GetNextMarked( nRow, bUp );
SCROW nRow1, nRow2;
nRow1 = aRowSel.GetNextMarked( nRow, bUp );
nRow2 = aIter->second.GetNextMarked( nRow, bUp );
nRow2 = aMultiSelContainer[nCol].GetNextMarked( nRow, bUp );
if ( nRow1 == nRow2 )
return nRow1;
if ( nRow1 == -1 )
@@ -195,11 +172,10 @@
void ScMultiSel::MarkAllCols( SCROW nStartRow, SCROW nEndRow )
{
MapType::iterator aIter = aMultiSelContainer.end();
aMultiSelContainer.resize(MAXCOL+1);
for ( SCCOL nCol = MAXCOL; nCol >= 0; --nCol )
{
aIter = aMultiSelContainer.emplace_hint( aIter, nCol, ScMarkArray() );
aIter->second.SetMarkArea( nStartRow, nEndRow, true );
aMultiSelContainer[nCol].SetMarkArea( nStartRow, nEndRow, true );
}
}
@@ -212,8 +188,8 @@
{
// Remove any per column marks for the row range.
for ( auto& aIter : aMultiSelContainer )
if ( aIter.second.HasMarks() )
aIter.second.SetMarkArea( nStartRow, nEndRow, false );
if ( aIter.HasMarks() )
aIter.SetMarkArea( nStartRow, nEndRow, false );
}
return;
}
@@ -253,14 +229,10 @@
aRowSel.SetMarkArea( nStartRow, nEndRow, false );
}
MapType::iterator aIter = aMultiSelContainer.end();
if (nEndCol >= static_cast<SCCOL>(aMultiSelContainer.size()))
aMultiSelContainer.resize(nEndCol+1);
for ( SCCOL nColIter = nEndCol; nColIter >= nStartCol; --nColIter )
{
// First hint is usually off, so the first emplace operation will take up to
// logarithmic in map size, all other iterations will take only constant time.
aIter = aMultiSelContainer.emplace_hint( aIter, nColIter, ScMarkArray() );
aIter->second.SetMarkArea( nStartRow, nEndRow, bMark );
}
aMultiSelContainer[nColIter].SetMarkArea( nStartRow, nEndRow, bMark );
}
bool ScMultiSel::IsRowMarked( SCROW nRow ) const
@@ -291,7 +263,7 @@
if ( aRowSel.HasMarks() )
return true;
for ( const auto& aPair : aMultiSelContainer )
if ( aPair.second.HasMarks() )
if ( aPair.HasMarks() )
return true;
return false;
}
@@ -307,66 +279,50 @@
if (nColOffset < 0)
{
// columns that would be moved on the left of nStartCol must be removed
const SCCOL nEndPos = nStartCol - nColOffset;
const SCCOL nEndPos = std::min<SCCOL>(aNewMultiSel.aMultiSelContainer.size(), nStartCol - nColOffset);
for (SCCOL nSearchPos = nStartCol; nSearchPos < nEndPos; ++nSearchPos)
{
const auto& aColIt = aNewMultiSel.aMultiSelContainer.find(nSearchPos);
if (aColIt != aNewMultiSel.aMultiSelContainer.end())
{
aNewMultiSel.aMultiSelContainer.erase(aColIt);
}
}
aNewMultiSel.aMultiSelContainer[nSearchPos].Reset();
}
MapType::iterator aDestEnd = aMultiSelContainer.end();
MapType::iterator aDestIter = aDestEnd;
for (const auto& aSourcePair : aNewMultiSel.aMultiSelContainer)
SCCOL nCol = 0;
for (const auto& aSourceArray : aNewMultiSel.aMultiSelContainer)
{
SCCOL nCol = aSourcePair.first;
if (aSourcePair.first >= nStartCol)
SCCOL nDestCol = nCol;
if (nDestCol >= nStartCol)
{
nCol += nColOffset;
if (nCol < 0)
nCol = 0;
else if (nCol > MAXCOL)
nCol = MAXCOL;
nDestCol += nColOffset;
if (nDestCol < 0)
nDestCol = 0;
else if (nDestCol > MAXCOL)
nDestCol = MAXCOL;
}
// correct hint is always aDestEnd as keys come in ascending order
// Amortized constant time operation as we always give the correct hint
aDestIter = aMultiSelContainer.emplace_hint( aDestEnd, nCol, ScMarkArray() );
aSourcePair.second.CopyMarksTo(aDestIter->second);
if (nDestCol >= static_cast<SCCOL>(aMultiSelContainer.size()))
aMultiSelContainer.resize(nDestCol);
aMultiSelContainer[nDestCol] = aSourceArray;
++nCol;
}
aNewMultiSel.aRowSel.CopyMarksTo(aRowSel);
aRowSel = aNewMultiSel.aRowSel;
if (nColOffset > 0 && nStartCol > 0)
if (nColOffset > 0 && nStartCol > 0 && nStartCol < static_cast<SCCOL>(aNewMultiSel.aMultiSelContainer.size()))
{
// insert nColOffset new columns, and select their cells if they are selected
// both in the old column at nStartPos and in the previous column
const auto& aPrevPosIt = aNewMultiSel.aMultiSelContainer.find(nStartCol - 1);
if (aPrevPosIt != aNewMultiSel.aMultiSelContainer.end())
{
const auto& aStartPosIt = aNewMultiSel.aMultiSelContainer.find(nStartCol);
if (aStartPosIt != aNewMultiSel.aMultiSelContainer.end())
{
MapType::iterator aNewColIt = aMultiSelContainer.emplace_hint(aDestEnd, nStartCol, ScMarkArray());
aStartPosIt->second.CopyMarksTo(aNewColIt->second);
aNewColIt->second.Intersect(aPrevPosIt->second);
for (long i = 1; i < nColOffset; ++i)
{
aDestIter = aMultiSelContainer.emplace_hint(aDestEnd, nStartCol + i, ScMarkArray());
aNewColIt->second.CopyMarksTo(aDestIter->second);
}
}
}
auto& rPrevPos = aNewMultiSel.aMultiSelContainer[nStartCol - 1];
auto& rStartPos = aNewMultiSel.aMultiSelContainer[nStartCol];
auto& rNewCol = aMultiSelContainer[nStartCol];
rNewCol = rStartPos;
rNewCol.Intersect(rPrevPos);
if (nStartCol + nColOffset >= static_cast<SCCOL>(aNewMultiSel.aMultiSelContainer.size()))
aNewMultiSel.aMultiSelContainer.resize(nStartCol + nColOffset);
for (long i = 1; i < nColOffset; ++i)
aMultiSelContainer[nStartCol + i] = rNewCol;
}
}
void ScMultiSel::ShiftRows(SCROW nStartRow, long nRowOffset)
{
for (auto& aPair: aMultiSelContainer)
{
aPair.second.Shift(nStartRow, nRowOffset);
}
aPair.Shift(nStartRow, nRowOffset);
aRowSel.Shift(nStartRow, nRowOffset);
}
@@ -377,8 +333,9 @@
const ScMarkArray* ScMultiSel::GetMultiSelArray( SCCOL nCol ) const
{
ScMultiSel::MapType::const_iterator aIter = aMultiSelContainer.find( nCol );
return (aIter != aMultiSelContainer.end()) ? &aIter->second : nullptr;
if (nCol >= static_cast<SCCOL>(aMultiSelContainer.size()))
return nullptr;
return &aMultiSelContainer[nCol];
}
ScMultiSelIter::ScMultiSelIter( const ScMultiSel& rMultiSel, SCCOL nCol ) :
@@ -386,8 +343,8 @@
nNextSegmentStart(0)
{
bool bHasMarks1 = rMultiSel.aRowSel.HasMarks();
ScMultiSel::MapType::const_iterator aIter = rMultiSel.aMultiSelContainer.find( nCol );
bool bHasMarks2 = ( ( aIter != rMultiSel.aMultiSelContainer.end() ) && aIter->second.HasMarks() );
bool bHasMarks2 = nCol < static_cast<SCCOL>(rMultiSel.aMultiSelContainer.size())
&& rMultiSel.aMultiSelContainer[nCol].HasMarks();
if (bHasMarks1 && bHasMarks2)
{
@@ -401,7 +358,7 @@
}
{
ScMarkArrayIter aMarkIter( &aIter->second );
ScMarkArrayIter aMarkIter( &rMultiSel.aMultiSelContainer[nCol] );
SCROW nTop, nBottom;
while ( aMarkIter.Next( nTop, nBottom ) )
pRowSegs->setTrue( nTop, nBottom );
@@ -413,7 +370,7 @@
}
else if (bHasMarks2)
{
aMarkArrayIter.reset( &aIter->second);
aMarkArrayIter.reset( &rMultiSel.aMultiSelContainer[nCol]);
}
}