sc/inc/queryiter.hxx              |    7 +++++--
 sc/source/core/data/queryiter.cxx |   33 ++++++++++++++++++++++++++++-----
 sc/source/core/inc/interpre.hxx   |    4 +++-
 sc/source/core/tool/interpr1.cxx  |   29 ++++++++++++++++++++---------
 sc/source/core/tool/interpr4.cxx  |   23 +++++++++++++++++++++++
 5 files changed, 79 insertions(+), 17 deletions(-)

New commits:
commit 4c8f4390c846e0184955916b0555359a6ad98981
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Tue May 10 10:54:26 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Wed May 11 11:51:16 2022 +0200

    do not use ScSortedRangeCache inefficiently
    
    If the amount of data or size of the formula group is small, the caching
    is probably not worth it. And if rows are not absolute, then each
    formula cell would use a different range instead of reusing the cache.
    
    Change-Id: I42a82aaa5f4ffccc63e527793f46fc52fd539af6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134129
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/inc/queryiter.hxx b/sc/inc/queryiter.hxx
index 545955d77963..7c454f784a2e 100644
--- a/sc/inc/queryiter.hxx
+++ b/sc/inc/queryiter.hxx
@@ -26,6 +26,7 @@
 #include "mtvelements.hxx"
 #include "types.hxx"
 
+struct ScComplexRefData;
 class ScSortedRangeCache;
 
 /*
@@ -318,7 +319,8 @@ public:
         SCTAB nTable, const ScQueryParam& aParam, bool bMod)
     : Base( rDocument, rContext, nTable, aParam, bMod ) {}
     // Returns true if this iterator can be used for the given query.
-    static bool CanBeUsed(const ScDocument& rDoc, const ScQueryParam& aParam);
+    static bool CanBeUsed(const ScDocument& rDoc, const ScQueryParam& aParam,
+        const ScFormulaCell* cell, const ScComplexRefData* refData);
 };
 
 
@@ -366,7 +368,8 @@ public:
         SCTAB nTable, const ScQueryParam& aParam, bool bMod)
     : Base( rDocument, rContext, nTable, aParam, bMod ) {}
     // Returns true if this iterator can be used for the given query.
-    static bool CanBeUsed(const ScDocument& rDoc, const ScQueryParam& aParam);
+    static bool CanBeUsed(const ScDocument& rDoc, const ScQueryParam& aParam,
+        const ScFormulaCell* cell, const ScComplexRefData* refData);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/queryiter.cxx 
b/sc/source/core/data/queryiter.cxx
index ffb37c0e272f..8a7bf2ce6e5b 100644
--- a/sc/source/core/data/queryiter.cxx
+++ b/sc/source/core/data/queryiter.cxx
@@ -1198,7 +1198,8 @@ ScQueryCellIteratorAccessSpecific< 
ScQueryCellIteratorAccess::SortedCache >::Mak
     return SortedCacheIndexer(rCells, nStartRow, nEndRow, sortedCache);
 }
 
-static bool CanBeUsedForSorterCache(const ScDocument& rDoc, const 
ScQueryParam& rParam)
+static bool CanBeUsedForSorterCache(const ScDocument& rDoc, const 
ScQueryParam& rParam,
+    const ScFormulaCell* cell, const ScComplexRefData* refData)
 {
     if(!rParam.GetEntry(0).bDoQuery || rParam.GetEntry(1).bDoQuery
         || rParam.GetEntry(0).GetQueryItems().size() != 1 )
@@ -1221,6 +1222,26 @@ static bool CanBeUsedForSorterCache(const ScDocument& 
rDoc, const ScQueryParam&
         && rParam.GetEntry(0).eOp != SC_GREATER && rParam.GetEntry(0).eOp != 
SC_GREATER_EQUAL
         && rParam.GetEntry(0).eOp != SC_EQUAL)
         return false;
+    // For unittests allow inefficient caching, in order for the code to be 
checked.
+    static bool inUnitTest = getenv("LO_TESTNAME") != nullptr;
+    if(refData == nullptr || refData->Ref1.IsRowRel() || 
refData->Ref2.IsRowRel())
+    {
+        // If this is not a range, then a cache is not worth it. If rows are 
relative, then each
+        // computation will use a different area, so the cache wouldn't be 
reused. Tab/cols are
+        // not a problem, because formula group computations are done for the 
same tab/col.
+        if(!inUnitTest)
+            return false;
+    }
+    if(rParam.nRow2 - rParam.nRow1 < 10)
+    {
+        if(!inUnitTest)
+            return false;
+    }
+    if( !cell || !cell->GetCellGroup() || cell->GetCellGroup()->mnLength < 10 )
+    {
+        if(!inUnitTest)
+            return false;
+    }
     return true;
 }
 
@@ -1260,9 +1281,10 @@ bool ScQueryCellIterator< accessType >::GetNext()
     return GetThis();
 }
 
-bool ScQueryCellIteratorSortedCache::CanBeUsed(const ScDocument& rDoc, const 
ScQueryParam& rParam)
+bool ScQueryCellIteratorSortedCache::CanBeUsed(const ScDocument& rDoc, const 
ScQueryParam& rParam,
+    const ScFormulaCell* cell, const ScComplexRefData* refData)
 {
-    return CanBeUsedForSorterCache(rDoc, rParam);
+    return CanBeUsedForSorterCache(rDoc, rParam, cell, refData);
 }
 
 // Countifs implementation.
@@ -1289,9 +1311,10 @@ sal_uInt64 ScCountIfCellIterator< accessType 
>::GetCount()
 }
 
 
-bool ScCountIfCellIteratorSortedCache::CanBeUsed(const ScDocument& rDoc, const 
ScQueryParam& rParam)
+bool ScCountIfCellIteratorSortedCache::CanBeUsed(const ScDocument& rDoc, const 
ScQueryParam& rParam,
+    const ScFormulaCell* cell, const ScComplexRefData* refData)
 {
-    return CanBeUsedForSorterCache(rDoc, rParam);
+    return CanBeUsedForSorterCache(rDoc, rParam, cell, refData);
 }
 
 template<>
diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index 47763ed8fea4..30e79d9272bb 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -345,6 +345,8 @@ private:
     ScDBRangeBase* PopDBDoubleRef();
     void PopDoubleRef(SCCOL& rCol1, SCROW &rRow1, SCTAB& rTab1,
                               SCCOL& rCol2, SCROW &rRow2, SCTAB& rTab2 );
+    // peek double ref data
+    const ScComplexRefData* GetStackDoubleRef(size_t rRefInList = 0);
 
     void PopExternalSingleRef(sal_uInt16& rFileId, OUString& rTabName, 
ScSingleRefData& rRef);
 
@@ -481,7 +483,7 @@ private:
     inline void TreatDoubleError( double& rVal );
     // Lookup using ScLookupCache, @returns true if found and result address
     bool LookupQueryWithCache( ScAddress & o_rResultPos,
-            const ScQueryParam & rParam ) const;
+            const ScQueryParam & rParam, const ScComplexRefData* refData ) 
const;
 
     void ScIfJump();
     void ScIfError( bool bNAonly );
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index e80b299f4771..afd9079de498 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -4839,6 +4839,7 @@ void ScInterpreter::ScMatch()
         rParam.nRow1       = nRow1;
         rParam.nCol2       = nCol2;
         rParam.nTab        = nTab1;
+        const ScComplexRefData* refData = nullptr;
 
         ScQueryEntry& rEntry = rParam.GetEntry(0);
         ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
@@ -4863,6 +4864,8 @@ void ScInterpreter::ScMatch()
             }
             break;
             case svDoubleRef :
+                refData = GetStackDoubleRef();
+                [[fallthrough]];
             case svSingleRef :
             {
                 ScAddress aAdr;
@@ -5037,7 +5040,7 @@ void ScInterpreter::ScMatch()
             rParam.nRow2 = nRow2;
             rEntry.nField = nCol1;
             ScAddress aResultPos( nCol1, nRow1, nTab1);
-            if (!LookupQueryWithCache( aResultPos, rParam))
+            if (!LookupQueryWithCache( aResultPos, rParam, refData))
             {
                 PushNA();
                 return;
@@ -5689,6 +5692,7 @@ void ScInterpreter::ScCountIf()
         SCROW nRow2 = 0;
         SCTAB nTab2 = 0;
         ScMatrixRef pQueryMatrix;
+        const ScComplexRefData* refData = nullptr;
         switch ( GetStackType() )
         {
             case svRefList :
@@ -5696,6 +5700,7 @@ void ScInterpreter::ScCountIf()
                 [[fallthrough]];
             case svDoubleRef :
                 {
+                    refData = GetStackDoubleRef(nRefInList);
                     ScRange aRange;
                     PopDoubleRef( aRange, nParam, nRefInList);
                     aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
@@ -5788,7 +5793,7 @@ void ScInterpreter::ScCountIf()
             }
             else
             {
-                if(ScCountIfCellIteratorSortedCache::CanBeUsed(mrDoc, rParam))
+                if(ScCountIfCellIteratorSortedCache::CanBeUsed(mrDoc, rParam, 
pMyFormulaCell, refData))
                 {
                     ScCountIfCellIteratorSortedCache aCellIter(mrDoc, 
mrContext, nTab1, rParam, false);
                     fCount += aCellIter.GetCount();
@@ -5979,6 +5984,7 @@ void ScInterpreter::IterateParametersIfs( 
double(*ResultFunc)( const sc::ParamIf
         ScMatrixRef pQueryMatrix;
         while (nParam-- == nParamCount)
         {
+            const ScComplexRefData* refData = nullptr;
             switch ( GetStackType() )
             {
                 case svRefList :
@@ -6015,12 +6021,14 @@ void ScInterpreter::IterateParametersIfs( 
double(*ResultFunc)( const sc::ParamIf
                             }
                             nRefArrayPos = nRefInList;
                         }
+                        refData = GetStackDoubleRef(nRefInList);
                         ScRange aRange;
                         PopDoubleRef( aRange, nParam, nRefInList);
                         aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, 
nTab2);
                     }
                 break;
                 case svDoubleRef :
+                    refData = GetStackDoubleRef();
                     PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
                 break;
                 case svSingleRef :
@@ -6150,7 +6158,7 @@ void ScInterpreter::IterateParametersIfs( 
double(*ResultFunc)( const sc::ParamIf
             }
             else
             {
-                if( ScQueryCellIteratorSortedCache::CanBeUsed( mrDoc, rParam ))
+                if( ScQueryCellIteratorSortedCache::CanBeUsed( mrDoc, rParam, 
pMyFormulaCell, refData ))
                 {
                     ScQueryCellIteratorSortedCache aCellIter(mrDoc, mrContext, 
nTab1, rParam, false);
                     // Increment Entry.nField in iterator when switching to 
next column.
@@ -7250,9 +7258,11 @@ void ScInterpreter::CalculateLookup(bool bHLookup)
     SCTAB nTab1 = 0;
     SCCOL nCol2 = 0;
     SCROW nRow2 = 0;
+    const ScComplexRefData* refData = nullptr;
     StackVar eType = GetStackType();
     if (eType == svDoubleRef)
     {
+        refData = GetStackDoubleRef(0);
         SCTAB nTab2;
         PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
         if (nTab1 != nTab2)
@@ -7467,7 +7477,7 @@ void ScInterpreter::CalculateLookup(bool bHLookup)
         else
         {
             ScAddress aResultPos( nCol1, nRow1, nTab1);
-            bFound = LookupQueryWithCache( aResultPos, aParam);
+            bFound = LookupQueryWithCache( aResultPos, aParam, refData);
             nRow = aResultPos.Row();
             nCol = nSpIndex;
         }
@@ -9967,7 +9977,8 @@ utl::SearchParam::SearchType 
ScInterpreter::DetectSearchType( std::u16string_vie
 }
 
 static bool lcl_LookupQuery( ScAddress & o_rResultPos, ScDocument& rDoc, 
ScInterpreterContext& rContext,
-        const ScQueryParam & rParam, const ScQueryEntry & rEntry )
+        const ScQueryParam & rParam, const ScQueryEntry & rEntry, const 
ScFormulaCell* cell,
+        const ScComplexRefData* refData )
 {
     if (rEntry.eOp != SC_EQUAL)
     {
@@ -9984,7 +9995,7 @@ static bool lcl_LookupQuery( ScAddress & o_rResultPos, 
ScDocument& rDoc, ScInter
     }
     else // EQUAL
     {
-        if( ScQueryCellIteratorSortedCache::CanBeUsed( rDoc, rParam ))
+        if( ScQueryCellIteratorSortedCache::CanBeUsed( rDoc, rParam, cell, 
refData ))
         {
             ScQueryCellIteratorSortedCache aCellIter( rDoc, rContext, 
rParam.nTab, rParam, false);
             if (aCellIter.GetFirst())
@@ -10047,7 +10058,7 @@ static SCROW lcl_getPrevRowWithEmptyValueLookup( const 
ScLookupCache& rCache,
 }
 
 bool ScInterpreter::LookupQueryWithCache( ScAddress & o_rResultPos,
-        const ScQueryParam & rParam ) const
+        const ScQueryParam & rParam, const ScComplexRefData* refData ) const
 {
     bool bFound = false;
     const ScQueryEntry& rEntry = rParam.GetEntry(0);
@@ -10060,7 +10071,7 @@ bool ScInterpreter::LookupQueryWithCache( ScAddress & 
o_rResultPos,
      * direct lookups here. We could even further attribute volatility per
      * parameter so it would affect only the lookup range parameter. */
     if (!bColumnsMatch || GetVolatileType() != NOT_VOLATILE)
-        bFound = lcl_LookupQuery( o_rResultPos, mrDoc, mrContext, rParam, 
rEntry);
+        bFound = lcl_LookupQuery( o_rResultPos, mrDoc, mrContext, rParam, 
rEntry, pMyFormulaCell, refData);
     else
     {
         ScRange aLookupRange( rParam.nCol1, rParam.nRow1, rParam.nTab,
@@ -10091,7 +10102,7 @@ bool ScInterpreter::LookupQueryWithCache( ScAddress & 
o_rResultPos,
         {
             case ScLookupCache::NOT_CACHED :
             case ScLookupCache::CRITERIA_DIFFERENT :
-                bFound = lcl_LookupQuery( o_rResultPos, mrDoc, mrContext, 
rParam, rEntry);
+                bFound = lcl_LookupQuery( o_rResultPos, mrDoc, mrContext, 
rParam, rEntry, pMyFormulaCell, refData);
                 if (eCacheResult == ScLookupCache::NOT_CACHED)
                     rCache.insert( o_rResultPos, aCriteria, aPos, bFound);
                 break;
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index 658cc2b5f9fd..540928f0bee6 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -1114,6 +1114,29 @@ void ScInterpreter::PopDoubleRef( ScRange& rRange, bool 
bDontCheckForTableOp )
         SetError( FormulaError::UnknownStackVariable);
 }
 
+const ScComplexRefData* ScInterpreter::GetStackDoubleRef(size_t rRefInList)
+{
+    if( sp )
+    {
+        const FormulaToken* p = pStack[ sp - 1 ];
+        switch (p->GetType())
+        {
+            case svDoubleRef:
+                return p->GetDoubleRef();
+            case svRefList:
+            {
+                const ScRefList* pList = p->GetRefList();
+                if (rRefInList < pList->size())
+                    return &(*pList)[rRefInList];
+                break;
+            }
+            default:
+                break;
+        }
+    }
+    return nullptr;
+}
+
 void ScInterpreter::PopExternalSingleRef(sal_uInt16& rFileId, OUString& 
rTabName, ScSingleRefData& rRef)
 {
     if (!sp)

Reply via email to