diff options
Diffstat (limited to 'sc/source/core/tool/compiler.cxx')
-rw-r--r-- | sc/source/core/tool/compiler.cxx | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index bb5efae527fd..144ca95d4113 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -6122,6 +6122,11 @@ void ScCompiler::PostProcessCode() mPendingImplicitIntersectionOptimizations.clear(); } +void ScCompiler::AnnotateOperands() +{ + AnnotateTrimOnDoubleRefs(); +} + void ScCompiler::ReplaceDoubleRefII(FormulaToken** ppDoubleRefTok) { const ScComplexRefData* pRange = (*ppDoubleRefTok)->GetDoubleRef(); @@ -6293,4 +6298,97 @@ void ScCompiler::CorrectSumRange(const ScComplexRefData& rBaseRange, pNewSumRangeTok->IncRef(); } +void ScCompiler::AnnotateTrimOnDoubleRefs() +{ + if (!pCode || !(pCode -1) || !(*(pCode - 1))) + return; + + // OpCode of the "root" operator (which is already in RPN array). + OpCode eOpCode = (*(pCode - 1))->GetOpCode(); + // eOpCode can be some operator which does not change with operands with or contains zero values. + if (eOpCode != ocSum) + return; + + FormulaToken** ppTok = pCode - 2; // exclude the root operator. + // The following loop runs till a "pattern" is found or there is a mismatch + // and marks the push DoubleRef arguments as trimmable when there is a match. + // The pattern is + // SUM(IF(<reference|double>=<reference|double>, <then-clause>)<a some operands with operators / or *>) + // such that one of the operands of ocEqual is a double-ref. + // Examples of formula that matches this are: + // SUM(IF(D:D=$A$1,F:F)*$H$1*2.3/$G$2) + // SUM((IF(D:D=$A$1,F:F)*$H$1*2.3/$G$2)*$H$2*5/$G$3) + // SUM(IF(E:E=16,F:F)*$H$1*100) + bool bTillClose = true; + bool bCloseTillIf = false; + sal_Int16 nToksTillIf = 0; + constexpr sal_Int16 MAXDIST_IF = 15; + while (*(ppTok)) + { + FormulaToken* pTok = *ppTok; + OpCode eCurrOp = pTok->GetOpCode(); + ++nToksTillIf; + + // TODO : Is there a better way to handle this ? + // ocIf is too far off from the sum opcode. + if (nToksTillIf > MAXDIST_IF) + return; + + switch (eCurrOp) + { + case ocDiv: + case ocMul: + if (!bTillClose) + return; + break; + case ocPush: + + break; + case ocClose: + if (bTillClose) + { + bTillClose = false; + bCloseTillIf = true; + } + else + return; + break; + case ocIf: + { + if (!bCloseTillIf) + return; + + if (!pTok->IsInForceArray()) + return; + + const short nJumpCount = pTok->GetJump()[0]; + if (nJumpCount != 2) // Should have THEN but no ELSE. + return; + + OpCode eCompOp = (*(ppTok - 1))->GetOpCode(); + if (eCompOp != ocEqual) + return; + + FormulaToken* pLHS = *(ppTok - 2); + FormulaToken* pRHS = *(ppTok - 3); + if (((pLHS->GetType() == svSingleRef || pLHS->GetType() == svDouble) && pRHS->GetType() == svDoubleRef) || + ((pRHS->GetType() == svSingleRef || pRHS->GetType() == svDouble) && pLHS->GetType() == svDoubleRef)) + { + if (pLHS->GetType() == svDoubleRef) + pLHS->GetDoubleRef()->SetTrimToData(true); + else + pRHS->GetDoubleRef()->SetTrimToData(true); + return; + } + } + break; + default: + return; + } + --ppTok; + } + + return; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |