sc/inc/global.hxx               |    1 -
 sc/inc/table.hxx                |    9 ++++++++-
 sc/source/core/data/dociter.cxx |    6 ++++--
 sc/source/core/data/global.cxx  |    6 ++----
 sc/source/core/data/table3.cxx  |   28 +++++++++++++++++++++++-----
 5 files changed, 37 insertions(+), 13 deletions(-)

New commits:
commit 1a32af4192291ea5cfe7c4c143144a5dab1f156e
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Mon Nov 22 13:16:43 2021 +0100
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Mon Nov 22 15:46:46 2021 +0100

    cache error strings for ScTable::validQuery()  (tdf#133835)
    
    Avoid calling SharedStringPool::intern() on values that are
    repeatedly the same.
    
    Change-Id: I094f2e777a4ca24536e0c25e6a1c6358ccf49f61
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125660
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 40806e70f31a..332be67ee551 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -954,10 +954,17 @@ public:
 
     void Reorder( const sc::ReorderParam& rParam );
 
+    // Internal cache that can be repeatedly used for a sequence of related 
ValidQuery()
+    // calls (related meaning done in a loop for the same document and query 
data).
+    struct ValidQueryCache
+    {
+        std::unordered_map<FormulaError, svl::SharedString> 
mCachedSharedErrorStrings;
+    };
     bool ValidQuery(
         SCROW nRow, const ScQueryParam& rQueryParam, const ScRefCellValue* 
pCell = nullptr,
         bool* pbTestEqualCondition = nullptr, const ScInterpreterContext* 
pContext = nullptr,
-        sc::TableColumnBlockPositionSet* pBlockPos = nullptr );
+        sc::TableColumnBlockPositionSet* pBlockPos = nullptr,
+        ValidQueryCache* pQueryCache = nullptr );
     void        TopTenQuery( ScQueryParam& );
     void        PrepareQuery( ScQueryParam& rQueryParam );
     SCSIZE      Query(const ScQueryParam& rQueryParam, bool bKeepSub);
diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx
index 378d867b4e55..91cc0a2c213c 100644
--- a/sc/source/core/data/dociter.cxx
+++ b/sc/source/core/data/dociter.cxx
@@ -1117,6 +1117,7 @@ bool ScQueryCellIterator::GetThis()
         !maParam.bHasHeader && rItem.meType == ScQueryEntry::ByString &&
         ((maParam.bByRow && nRow == maParam.nRow1) ||
          (!maParam.bByRow && nCol == maParam.nCol1));
+    ScTable::ValidQueryCache validQueryCache;
 
     ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
     while (true)
@@ -1183,7 +1184,7 @@ bool ScQueryCellIterator::GetThis()
             if ( rDoc.maTabs[nTab]->ValidQuery( nRow, maParam,
                     (nCol == static_cast<SCCOL>(nFirstQueryField) ? &aCell : 
nullptr),
                     (nTestEqualCondition ? &bTestEqualCondition : nullptr),
-                    &mrContext) )
+                    &mrContext, nullptr, &validQueryCache) )
             {
                 if ( nTestEqualCondition && bTestEqualCondition )
                     nTestEqualCondition |= nTestEqualConditionMatched;
@@ -1506,6 +1507,7 @@ int ScCountIfCellIterator::GetCount()
     const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
     const bool bSingleQueryItem = rEntry.GetQueryItems().size() == 1;
     int count = 0;
+    ScTable::ValidQueryCache validQueryCache;
 
     ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
     while (true)
@@ -1561,7 +1563,7 @@ int ScCountIfCellIterator::GetCount()
         if ( rDoc.maTabs[nTab]->ValidQuery( nRow, maParam,
                 (nCol == static_cast<SCCOL>(rEntry.nField) ? &aCell : nullptr),
                 nullptr,
-                &mrContext) )
+                &mrContext, nullptr, &validQueryCache) )
         {
             if (aCell.isEmpty())
                 return count;
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 0ef833511dba..6ff12c4a25b5 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -2330,6 +2330,7 @@ class QueryEvaluator
     CollatorWrapper* mpCollator;
     const bool mbMatchWholeCell;
     const bool mbCaseSensitive;
+    ScTable::ValidQueryCache* mpValidQueryCache;
 
     static bool isPartialTextMatchOp(const ScQueryEntry& rEntry)
     {
@@ -2399,7 +2400,7 @@ class QueryEvaluator
 
 public:
     QueryEvaluator(ScDocument& rDoc, const ScTable& rTab, const ScQueryParam& 
rParam,
-                   bool pTestEqualCondition) :
+                   bool pTestEqualCondition, ScTable::ValidQueryCache* 
pValidQueryCache) :
         mrDoc(rDoc),
         mrStrPool(rDoc.GetSharedStringPool()),
         mrTab(rTab),
@@ -2408,7 +2409,8 @@ public:
         mpTransliteration(nullptr),
         mpCollator(nullptr),
         mbMatchWholeCell(rDoc.GetDocOptions().IsMatchWholeCell()),
-        mbCaseSensitive( rParam.bCaseSens )
+        mbCaseSensitive( rParam.bCaseSens ),
+        mpValidQueryCache( pValidQueryCache )
     {
     }
 
@@ -2595,6 +2597,20 @@ public:
             if (rCell.meType == CELLTYPE_FORMULA && 
rCell.mpFormula->GetErrCode() != FormulaError::NONE)
             {
                 // Error cell is evaluated as string (for now).
+                if(mpValidQueryCache)
+                {
+                    const FormulaError error = rCell.mpFormula->GetErrCode();
+                    auto it = 
mpValidQueryCache->mCachedSharedErrorStrings.find(error);
+                    if( it == 
mpValidQueryCache->mCachedSharedErrorStrings.end())
+                    {
+                        svl::SharedString str = 
mrStrPool.intern(ScGlobal::GetErrorString(error));
+                        auto pos = 
mpValidQueryCache->mCachedSharedErrorStrings.insert({error, str});
+                        assert(pos.second); // inserted
+                        it = pos.first;
+                    }
+                    const svl::SharedString& sharedError = it->second;
+                    return compareByStringComparator(rEntry, rItem, 
&sharedError, nullptr);
+                }
                 const OUString aCellStr = 
ScGlobal::GetErrorString(rCell.mpFormula->GetErrCode());
                 return compareByStringComparator(rEntry, rItem, nullptr, 
&aCellStr);
             }
@@ -2976,7 +2992,8 @@ public:
 
 bool ScTable::ValidQuery(
     SCROW nRow, const ScQueryParam& rParam, const ScRefCellValue* pCell, bool* 
pbTestEqualCondition,
-    const ScInterpreterContext* pContext, sc::TableColumnBlockPositionSet* 
pBlockPos)
+    const ScInterpreterContext* pContext, sc::TableColumnBlockPositionSet* 
pBlockPos,
+    ValidQueryCache* pValidQueryCache)
 {
     if (!rParam.GetEntry(0).bDoQuery)
         return true;
@@ -2991,7 +3008,7 @@ bool ScTable::ValidQuery(
     bool* pTest = ( nEntryCount <= nFixedBools ? &aTest[0] : new 
bool[nEntryCount] );
 
     tools::Long    nPos = -1;
-    QueryEvaluator aEval(rDocument, *this, rParam, pbTestEqualCondition != 
nullptr);
+    QueryEvaluator aEval(rDocument, *this, rParam, pbTestEqualCondition != 
nullptr, pValidQueryCache);
     ScQueryParam::const_iterator it, itBeg = rParam.begin(), itEnd = 
rParam.end();
     for (it = itBeg; it != itEnd && (*it)->bDoQuery; ++it)
     {
@@ -3389,12 +3406,13 @@ SCSIZE ScTable::Query(const ScQueryParam& rParamOrg, 
bool bKeepSub)
     }
 
     sc::TableColumnBlockPositionSet blockPos( GetDoc(), nTab ); // cache mdds 
access
+    ValidQueryCache validQueryCache;
 
     SCROW nRealRow2 = aParam.nRow2;
     for (SCROW j = aParam.nRow1 + nHeader; j <= nRealRow2; ++j)
     {
         bool bResult;                                   // Filter result
-        bool bValid = ValidQuery(j, aParam, nullptr, nullptr, nullptr, 
&blockPos);
+        bool bValid = ValidQuery(j, aParam, nullptr, nullptr, nullptr, 
&blockPos, &validQueryCache);
         if (!bValid && bKeepSub)                        // Keep subtotals
         {
             for (SCCOL nCol=aParam.nCol1; nCol<=aParam.nCol2 && !bValid; 
nCol++)
commit 2de99501b7d7b32867d23d4089197e132c6a0526
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Mon Nov 22 10:35:48 2021 +0100
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Mon Nov 22 15:46:32 2021 +0100

    Revert "cache FormulaError::NoRef error string (tdf#144249)"
    
    A more generic fix coming.
    
    This reverts commit b4c1bb2f91e9ae47820c289e2c08f640a958cf05.
    
    Change-Id: Ia7821f1c8585506556708f1bf8526e7f509aafd1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125659
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/inc/global.hxx b/sc/inc/global.hxx
index 3eab2e36d8e2..dad30b02e7a8 100644
--- a/sc/inc/global.hxx
+++ b/sc/inc/global.hxx
@@ -496,7 +496,6 @@ class ScGlobal
     static std::atomic<ScUnoAddInCollection*> pAddInCollection;
     static std::unique_ptr<ScUserList> xUserList;
     static OUString         aStrClipDocName;
-    static OUString         aStrErrorStringNoRef;
     static std::unique_ptr<SvxBrushItem> xEmptyBrushItem;
     static std::unique_ptr<SvxBrushItem> xButtonBrushItem;
 
diff --git a/sc/source/core/data/global.cxx b/sc/source/core/data/global.cxx
index 60c0afb1ecf2..e29fccf5c1b2 100644
--- a/sc/source/core/data/global.cxx
+++ b/sc/source/core/data/global.cxx
@@ -88,7 +88,6 @@ std::atomic<::utl::TransliterationWrapper*> 
ScGlobal::pTransliteration(nullptr);
 std::atomic<::utl::TransliterationWrapper*> 
ScGlobal::pCaseTransliteration(nullptr);
 css::uno::Reference< css::i18n::XOrdinalSuffix> ScGlobal::xOrdinalSuffix;
 OUString        ScGlobal::aStrClipDocName;
-OUString        ScGlobal::aStrErrorStringNoRef;
 
 std::unique_ptr<SvxBrushItem> ScGlobal::xEmptyBrushItem;
 std::unique_ptr<SvxBrushItem> ScGlobal::xButtonBrushItem;
@@ -305,8 +304,8 @@ OUString ScGlobal::GetErrorString(FormulaError nErr)
     switch (nErr)
     {
         case FormulaError::NoRef:
-            // tdf#144249 This may get called very extensively, so cached.
-            return aStrErrorStringNoRef;
+            pErrNumber = STR_NO_REF_TABLE;
+            break;
         case FormulaError::NoAddin:
             pErrNumber = STR_NO_ADDIN;
             break;
@@ -452,7 +451,6 @@ void ScGlobal::Init()
     InitAddIns();
 
     aStrClipDocName = ScResId( SCSTR_NONAME ) + "1";
-    aStrErrorStringNoRef = ScResId( STR_NO_REF_TABLE );
 
     //  ScDocumentPool::InitVersionMaps() has been called earlier already
 }

Reply via email to