tdf#126021 speed up saving xls with lots of styles
extend the find-map so we can do partial-match searching.
Makes it 10x faster for me.
Change-Id: I1952a221a919707af078fac9fd1eb63781d9188d
Reviewed-on: https://gerrit.libreoffice.org/81488
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/sc/source/filter/excel/xestyle.cxx b/sc/source/filter/excel/xestyle.cxx
index 7f3ac9c..7b6a3b5a 100644
--- a/sc/source/filter/excel/xestyle.cxx
+++ b/sc/source/filter/excel/xestyle.cxx
@@ -2666,24 +2666,58 @@ void XclExpXFBuffer::SaveXFXml( XclExpXmlStream& rStrm, XclExpXF& rXF )
sal_uInt32 XclExpXFBuffer::FindXF( const ScPatternAttr& rPattern,
sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
{
auto it = maXFFindMap.find(&rPattern.GetItemSet());
if (it == maXFFindMap.end())
return EXC_XFID_NOTFOUND;
for (auto const & nPos : it->second)
if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
return nPos;
if (nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND && nForceXclFont == EXC_FONT_NOTFOUND)
{
FindKey key1 { /*mbCellXF*/true, &rPattern.GetItemSet(), nForceScNumFmt, 0 };
FindKey key2 { /*mbCellXF*/true, &rPattern.GetItemSet(), nForceScNumFmt, EXC_FONT_NOTFOUND };
auto it1 = maXFFindMap.lower_bound(key1);
if (it1 != maXFFindMap.end())
{
auto it2 = maXFFindMap.upper_bound(key2);
for (auto it = it1; it != it2; ++it)
for (auto const & nPos : it->second)
if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
return nPos;
}
}
else if (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND || nForceXclFont == EXC_FONT_NOTFOUND)
{
FindKey key1 { /*mbCellXF*/true, &rPattern.GetItemSet(), 0, 0 };
FindKey key2 { /*mbCellXF*/true, &rPattern.GetItemSet(), NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND };
auto it1 = maXFFindMap.lower_bound(key1);
if (it1 != maXFFindMap.end())
{
auto it2 = maXFFindMap.upper_bound(key2);
for (auto it = it1; it != it2; ++it)
for (auto const & nPos : it->second)
if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
return nPos;
}
}
else
{
FindKey key { /*mbCellXF*/true, &rPattern.GetItemSet(), nForceScNumFmt, nForceXclFont };
auto it = maXFFindMap.find(key);
if (it == maXFFindMap.end())
return EXC_XFID_NOTFOUND;
for (auto const & nPos : it->second)
if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
return nPos;
}
return EXC_XFID_NOTFOUND;
}
sal_uInt32 XclExpXFBuffer::FindXF( const SfxStyleSheetBase& rStyleSheet ) const
{
const SfxItemSet* pItemSet = &const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet();
auto it = maXFFindMap.find(pItemSet);
if (it == maXFFindMap.end())
return EXC_XFID_NOTFOUND;
for (auto const & nPos : it->second)
if( maXFList.GetRecord( nPos )->Equals( rStyleSheet ) )
return nPos;
FindKey key1 { /*mbCellXF*/false, pItemSet, 0, 0 };
FindKey key2 { /*mbCellXF*/false, pItemSet, NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND };
auto it1 = maXFFindMap.lower_bound(key1);
auto it2 = maXFFindMap.upper_bound(key2);
for (auto it = it1; it != it2; ++it)
for (auto const & nPos : it->second)
if( maXFList.GetRecord( nPos )->Equals( rStyleSheet ) )
return nPos;
return EXC_XFID_NOTFOUND;
}
@@ -2698,6 +2732,11 @@ sal_uInt32 XclExpXFBuffer::FindBuiltInXF( sal_uInt8 nStyleId, sal_uInt8 nLevel )
return EXC_XFID_NOTFOUND;
}
XclExpXFBuffer::FindKey XclExpXFBuffer::ToFindKey(XclExpXF const & rRec)
{
return { rRec.IsCellXF(), rRec.GetItemSet(), rRec.GetScNumFmt(), rRec.GetXclFont() };
}
sal_uInt32 XclExpXFBuffer::InsertCellXF( const ScPatternAttr* pPattern, sal_Int16 nScript,
sal_uInt32 nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak )
{
@@ -2715,14 +2754,14 @@ sal_uInt32 XclExpXFBuffer::InsertCellXF( const ScPatternAttr* pPattern, sal_Int1
if( rbPredefined )
{
// remove old entry in find-map
auto & rPositions = maXFFindMap[maXFList.GetRecord(EXC_XF_DEFAULTCELL)->GetItemSet()];
auto & rPositions = maXFFindMap[ToFindKey(*maXFList.GetRecord(EXC_XF_DEFAULTCELL))];
auto it = std::find(rPositions.begin(), rPositions.end(), EXC_XF_DEFAULTCELL);
rPositions.erase(it);
// replace default cell pattern
XclExpXFRef xNewXF( new XclExpXF( GetRoot(), *pPattern, nScript ) );
maXFList.ReplaceRecord( xNewXF, EXC_XF_DEFAULTCELL );
// and add new entry in find-map
maXFFindMap[xNewXF->GetItemSet()].push_back(EXC_XF_DEFAULTCELL);
maXFFindMap[ToFindKey(*xNewXF)].push_back(EXC_XF_DEFAULTCELL);
rbPredefined = false;
}
return GetDefCellXFId();
@@ -2739,7 +2778,7 @@ sal_uInt32 XclExpXFBuffer::InsertCellXF( const ScPatternAttr* pPattern, sal_Int1
maXFList.AppendNewRecord( pNewExp );
// do not set nXFId before the AppendNewRecord() call - it may insert 2 XFs (style+cell)
nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() - 1 );
maXFFindMap[pNewExp->GetItemSet()].push_back(nXFId);
maXFFindMap[ToFindKey(*pNewExp)].push_back(nXFId);
}
else
{
@@ -2775,14 +2814,14 @@ sal_uInt32 XclExpXFBuffer::InsertStyleXF( const SfxStyleSheetBase& rStyleSheet )
if( rbPredefined )
{
// remove old entry in find-map
auto & rPositions = maXFFindMap[maXFList.GetRecord(nXFId)->GetItemSet()];
auto & rPositions = maXFFindMap[ToFindKey(*maXFList.GetRecord(nXFId))];
auto it = std::find(rPositions.begin(), rPositions.end(), nXFId);
rPositions.erase(it);
// replace predefined built-in style (ReplaceRecord() deletes old record)
auto pNewExp = std::make_shared<XclExpXF>( GetRoot(), rStyleSheet );
maXFList.ReplaceRecord( pNewExp, nXFId );
// and add new entry in find-map
maXFFindMap[pNewExp->GetItemSet()].push_back(nXFId);
maXFFindMap[ToFindKey(*pNewExp)].push_back(nXFId);
rbPredefined = false;
}
}
@@ -2812,7 +2851,7 @@ sal_uInt32 XclExpXFBuffer::InsertStyleXF( const SfxStyleSheetBase& rStyleSheet )
// create the STYLE record
if( !rStyleSheet.GetName().isEmpty() )
maStyleList.AppendNewRecord( new XclExpStyle( nXFId, rStyleSheet.GetName() ) );
maXFFindMap[pNewExp->GetItemSet()].push_back(nXFId);
maXFFindMap[ToFindKey(*pNewExp)].push_back(nXFId);
}
else
// list full - fall back to default style XF
@@ -2833,7 +2872,7 @@ sal_uInt32 XclExpXFBuffer::AppendBuiltInXF( XclExpXFRef const & xXF, sal_uInt8 n
{
sal_uInt32 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
maXFList.AppendRecord( xXF );
maXFFindMap[xXF->GetItemSet()].push_back(nXFId);
maXFFindMap[ToFindKey(*xXF)].push_back(nXFId);
XclExpBuiltInInfo& rInfo = maBuiltInMap[ nXFId ];
rInfo.mnStyleId = nStyleId;
rInfo.mnLevel = nLevel;
@@ -2906,7 +2945,7 @@ void XclExpXFBuffer::InsertDefaultRecords()
// index 15: default hard cell format, placeholder to be able to add more built-in styles
maXFList.AppendNewRecord( new XclExpDefaultXF( GetRoot(), true ) );
maXFFindMap[maXFList.GetRecord(maXFList.GetSize()-1)->GetItemSet()].push_back(maXFList.GetSize()-1);
maXFFindMap[ToFindKey(*maXFList.GetRecord(maXFList.GetSize()-1))].push_back(maXFList.GetSize()-1);
maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined = true;
// index 16-20: other built-in styles
diff --git a/sc/source/filter/inc/xestyle.hxx b/sc/source/filter/inc/xestyle.hxx
index 48b1e53..ae96053 100644
--- a/sc/source/filter/inc/xestyle.hxx
+++ b/sc/source/filter/inc/xestyle.hxx
@@ -30,6 +30,7 @@
#include <fonthelper.hxx>
#include <memory>
#include <vector>
#include <o3tl/sorted_vector.hxx>
/* ============================================================================
- Buffers for style records (PALETTE, FONT, FORMAT, XF, STYLE).
@@ -470,6 +471,9 @@ public:
const SfxItemSet* GetItemSet() const { return mpItemSet; }
sal_uInt32 GetScNumFmt() const { return mnScNumFmt; }
sal_uInt16 GetXclFont() const { return mnXclFont; }
protected:
explicit XclExpXF( const XclExpRoot& rRoot, bool bCellXF );
@@ -681,8 +685,29 @@ private:
typedef ::std::vector< XclExpCellBorder > XclExpBorderList;
typedef ::std::vector< XclExpCellArea > XclExpFillList;
/** composite key for the find-map, so we can do partial key searching */
struct FindKey
{
bool mbCellXF; // is this a hard cell format, or a cell style
const SfxItemSet* mpItemSet;
sal_uInt32 mnScNumFmt;
sal_uInt16 mnXclFont;
bool operator<(const FindKey& other) const
{
if (mbCellXF != other.mbCellXF)
return mbCellXF < other.mbCellXF;
if (mpItemSet != other.mpItemSet)
return mpItemSet < other.mpItemSet;
if (mnScNumFmt != other.mnScNumFmt)
return mnScNumFmt < other.mnScNumFmt;
return mnXclFont < other.mnXclFont;
}
};
static FindKey ToFindKey(XclExpXF const &);
XclExpXFList maXFList; /// List of all XF records.
std::unordered_map<const SfxItemSet*, std::vector<sal_uInt32>>
std::map<FindKey, std::vector<sal_uInt32>>
maXFFindMap; /// map of itemset to vector of positions, to speed up find
XclExpStyleList maStyleList; /// List of all STYLE records.
XclExpBuiltInMap maBuiltInMap; /// Contained elements describe built-in XFs.