20 #include <config_feature_opencl.h>
24 #include <osl/diagnose.h>
32 #include <compiler.hxx>
33 #include <document.hxx>
43 #include <progress.hxx>
50 #include <tokenarray.hxx>
68 #include <com/sun/star/sheet/FormulaLanguage.hpp>
70 #if HAVE_FEATURE_OPENCL
80 #define DEBUG_CALCULATION 0
82 static bool bDebugCalculationActive =
false;
83 static ScAddress aDebugCalculationTriggerAddress(1,2,0);
85 struct DebugCalculationEntry
91 sal_uInt16 mnRecursion;
97 mnRecursion(rDoc.GetRecursionHelper().GetRecursionCount())
108 static struct DebugCalculation
110 std::vector< DebugCalculationEntry > mvPos;
111 std::vector< DebugCalculationEntry > mvResults;
119 DebugCalculation() : mnGroup(0), mbActive(bDebugCalculationActive), mbSwitchOff(false),
120 mbPrint(true), mbPrintResults(false) {}
125 for (
auto const& it : mvPos)
128 " [" + OUString::number( it.mnRecursion) +
"," + OUString::number( it.mnGroup) +
"]");
129 fprintf( stderr,
"%s -> ",
aStr.toUtf8().getStr());
131 fprintf( stderr,
"%s",
"END\n");
135 void printResults()
const
137 for (
auto const& it : mvResults)
140 aStr +=
" (" + it.maResult +
")";
141 fprintf( stderr,
"%s, ", aStr.toUtf8().getStr());
143 fprintf( stderr,
"%s",
"END\n");
148 if (mbActive && !mvPos.empty())
149 mvPos.back().maResult =
"\"" + rStr.
getString() +
"\"";
152 void storeResult(
const double& fVal )
154 if (mbActive && !mvPos.empty())
155 mvPos.back().maResult = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_G, 2,
'.',
true);
160 if (mbActive && !mvPos.empty())
161 mvPos.back().maResult =
"Err:" + OUString::number(
int( nErr ));
176 struct DebugCalculationStacker
180 if (!aDC.mbActive && rPos == aDC.maTrigger)
181 aDC.mbActive = aDC.mbSwitchOff =
true;
184 aDC.mvPos.push_back( DebugCalculationEntry( rPos, rDoc, aDC.mnGroup));
189 ~DebugCalculationStacker()
193 if (!aDC.mvPos.empty())
200 if (aDC.mbPrintResults)
203 aDC.mvResults.push_back( aDC.mvPos.back());
205 aDC.mvPos.pop_back();
206 if (aDC.mbPrintResults && aDC.mvPos.empty())
209 std::vector< DebugCalculationEntry >().
swap( aDC.mvResults);
211 if (aDC.mbSwitchOff && aDC.mvPos.empty())
212 aDC.mbActive =
false;
234 return rData.
toAbs(rDoc, rPos).
Col();
239 return rData.
toAbs(rDoc, rPos).
Row();
244 return rData.
toAbs(rDoc, rPos).
Tab();
250 lcl_checkRangeDimension(
251 const ScDocument& rDoc,
253 const DimensionSelector aWhich)
255 return aWhich(rDoc, rPos, rRef1.
Ref1) == aWhich(rDoc, rPos, rRef2.
Ref1) &&
256 aWhich(rDoc, rPos, rRef1.
Ref2) == aWhich(rDoc, rPos, rRef2.
Ref2);
260 lcl_checkRangeDimensions(
261 const ScDocument& rDoc,
263 bool& bCol,
bool& bRow,
bool& bTab)
265 const bool bSameCols(lcl_checkRangeDimension(rDoc, rPos, rRef1, rRef2, lcl_GetCol));
266 const bool bSameRows(lcl_checkRangeDimension(rDoc, rPos, rRef1, rRef2, lcl_GetRow));
267 const bool bSameTabs(lcl_checkRangeDimension(rDoc, rPos, rRef1, rRef2, lcl_GetTab));
270 if (
int(bSameCols) +
int(bSameRows) +
int(bSameTabs) == 2)
284 lcl_checkRangeDimensions(
285 const ScDocument& rDoc,
const ScAddress& rPos,
286 const std::vector<formula::FormulaToken*>::const_iterator& rBegin,
287 const std::vector<formula::FormulaToken*>::const_iterator& rEnd,
288 bool& bCol,
bool& bRow,
bool& bTab)
290 std::vector<formula::FormulaToken*>::const_iterator aCur(rBegin);
296 bOk = lcl_checkRangeDimensions(rDoc, rPos, aRef, aRefCur, bCol, bRow, bTab);
298 while (bOk && aCur != rEnd)
304 bOk = lcl_checkRangeDimensions(rDoc, rPos, aRef, aRefCur, bColTmp, bRowTmp, bTabTmp);
305 bOk = bOk && (bCol == bColTmp && bRow == bRowTmp && bTab == bTabTmp);
309 return bOk && aCur == rEnd;
312 class LessByReference
314 const ScDocument& mrDoc;
318 LessByReference(
const ScDocument& rDoc,
const ScAddress& rPos,
const DimensionSelector& rFunc) :
319 mrDoc(rDoc), maPos(rPos), maFunc(rFunc) {}
325 return maFunc(mrDoc, maPos, aRef1.Ref1) < maFunc(mrDoc, maPos, aRef2.Ref1);
334 class AdjacentByReference
336 const ScDocument& mrDoc;
340 AdjacentByReference(
const ScDocument& rDoc,
const ScAddress& rPos, DimensionSelector aFunc) :
341 mrDoc(rDoc), maPos(rPos), maFunc(aFunc) {}
347 return maFunc(mrDoc, maPos, aRef2.Ref1) - maFunc(mrDoc, maPos, aRef1.Ref2) == 1;
353 const ScDocument& rDoc,
354 const ScAddress& rPos,
const std::vector<formula::FormulaToken*>& rReferences,
const DimensionSelector aWhich)
356 auto aBegin(rReferences.cbegin());
357 auto aEnd(rReferences.cend());
358 auto aBegin1(aBegin);
361 return std::equal(aBegin, aEnd, aBegin1, AdjacentByReference(rDoc, rPos, aWhich));
365 lcl_fillRangeFromRefList(
366 const ScDocument& rDoc,
367 const ScAddress& aPos,
const std::vector<formula::FormulaToken*>& rReferences,
ScRange& rRange)
371 rRange.
aStart = aStart.toAbs(rDoc, aPos);
374 rRange.
aEnd = aEnd.toAbs(rDoc, aPos);
378 lcl_refListFormsOneRange(
379 const ScDocument& rDoc,
380 const ScAddress& rPos, std::vector<formula::FormulaToken*>& rReferences,
383 if (rReferences.size() == 1)
385 lcl_fillRangeFromRefList(rDoc, rPos, rReferences, rRange);
392 if (lcl_checkRangeDimensions(rDoc, rPos, rReferences.begin(), rReferences.end(), bCell, bRow, bTab))
394 DimensionSelector aWhich;
409 OSL_FAIL(
"lcl_checkRangeDimensions shouldn't allow that!");
414 std::sort(rReferences.begin(), rReferences.end(), LessByReference(rDoc, rPos, aWhich));
415 if (lcl_checkIfAdjacent(rDoc, rPos, rReferences, aWhich))
417 lcl_fillRangeFromRefList(rDoc, rPos, rReferences, rRange);
432 const ScAddress& rNewPos,
const ScAddress& rOldPos,
bool bGlobalNamesToLocal)
437 if (!rOldDoc.
CopyAdjustRangeName( nSheet, nIndex, pRangeData, rNewDoc, rNewPos, rOldPos, bGlobalNamesToLocal,
true))
444 OSL_FAIL(
"inserting the range name should not fail");
455 if (!pOldDBCollection)
465 if (!pNewDBCollection)
474 pNewDBData =
new ScDBData(*pDBData);
475 bool ins = aNewNamedDBs.
insert(std::unique_ptr<ScDBData>(pNewDBData));
481 struct AreaListenerKey
487 AreaListenerKey(
const ScRange& rRange,
bool bStartFixed,
bool bEndFixed ) :
488 maRange(rRange), mbStartFixed(bStartFixed), mbEndFixed(bEndFixed) {}
490 bool operator < (
const AreaListenerKey& r )
const
492 if (maRange.
aStart.
Tab() != r.maRange.aStart.Tab())
493 return maRange.
aStart.
Tab() < r.maRange.aStart.Tab();
494 if (maRange.
aStart.
Col() != r.maRange.aStart.Col())
495 return maRange.
aStart.
Col() < r.maRange.aStart.Col();
496 if (maRange.
aStart.
Row() != r.maRange.aStart.Row())
497 return maRange.
aStart.
Row() < r.maRange.aStart.Row();
498 if (maRange.
aEnd.
Tab() != r.maRange.aEnd.Tab())
499 return maRange.
aEnd.
Tab() < r.maRange.aEnd.Tab();
500 if (maRange.
aEnd.
Col() != r.maRange.aEnd.Col())
501 return maRange.
aEnd.
Col() < r.maRange.aEnd.Col();
502 if (maRange.
aEnd.
Row() != r.maRange.aEnd.Row())
503 return maRange.
aEnd.
Row() < r.maRange.aEnd.Row();
504 if (mbStartFixed != r.mbStartFixed)
505 return r.mbStartFixed;
506 if (mbEndFixed != r.mbEndFixed)
513 typedef std::map<AreaListenerKey, std::unique_ptr<sc::FormulaGroupAreaListener>> AreaListenersType;
531 mbPartOfCycle(false),
549 mpCode = std::move(pCode);
561 if (
mpCode->GetLen() &&
mpCode->GetCodeError() == FormulaError::NONE && !
mpCode->GetCodeLen())
577 AreaListenerKey aKey(rRange, bStartFixed, bEndFixed);
579 AreaListenersType::iterator it =
mpImpl->m_AreaListeners.lower_bound(aKey);
580 if (it ==
mpImpl->m_AreaListeners.end() ||
mpImpl->m_AreaListeners.key_comp()(aKey, it->first))
583 it =
mpImpl->m_AreaListeners.insert(
584 it, std::make_pair(aKey, std::make_unique<sc::FormulaGroupAreaListener>(
585 rRange, (*ppTopCell)->GetDocument(), (*ppTopCell)->aPos,
mnLength, bStartFixed, bEndFixed)));
588 return it->second.get();
593 for (
const auto& rEntry :
mpImpl->m_AreaListeners)
602 mpImpl->m_AreaListeners.clear();
607 bTableOpDirty(false),
613 bInChangeTrack(false),
614 bNeedListening(false),
615 mbNeedsNumberFormat(false),
616 mbAllowNumberFormatChange(false),
617 mbPostponedDirty(false),
628 pPreviousTrack(nullptr),
635 const OUString& rFormula,
639 bTableOpDirty( false ),
644 bIsIterCell( false ),
645 bInChangeTrack( false ),
646 bNeedListening( false ),
647 mbNeedsNumberFormat( false ),
648 mbAllowNumberFormatChange(false),
649 mbPostponedDirty(false),
652 cMatrixFlag ( cMatInd ),
655 eTempGrammar( eGrammar),
660 pPreviousTrack(nullptr),
664 Compile( rFormula,
true, eGrammar );
671 ScDocument& rDoc,
const ScAddress& rPos, std::unique_ptr<ScTokenArray> pArray,
674 bTableOpDirty( false ),
679 bIsIterCell( false ),
680 bInChangeTrack( false ),
681 bNeedListening( false ),
682 mbNeedsNumberFormat( false ),
683 mbAllowNumberFormatChange(false),
684 mbPostponedDirty(false),
687 cMatrixFlag ( cMatInd ),
690 eTempGrammar( eGrammar),
691 pCode(pArray.release()),
695 pPreviousTrack(nullptr),
723 ScDocument& rDoc,
const ScAddress& rPos,
const ScTokenArray& rArray,
726 bTableOpDirty( false ),
731 bIsIterCell( false ),
732 bInChangeTrack( false ),
733 bNeedListening( false ),
734 mbNeedsNumberFormat( false ),
735 mbAllowNumberFormatChange(false),
736 mbPostponedDirty(false),
739 cMatrixFlag ( cMatInd ),
742 eTempGrammar( eGrammar),
747 pPreviousTrack(nullptr),
775 bTableOpDirty( false ),
779 bSubTotal(xGroup->mbSubTotal),
780 bIsIterCell( false ),
781 bInChangeTrack( false ),
782 bNeedListening( false ),
783 mbNeedsNumberFormat( false ),
784 mbAllowNumberFormatChange(false),
785 mbPostponedDirty(false),
788 cMatrixFlag ( cInd ),
790 nFormatType(xGroup->mnFormatType),
791 eTempGrammar( eGrammar),
796 pPreviousTrack(nullptr),
806 bDirty( rCell.bDirty ),
807 bTableOpDirty( false ),
808 bChanged( rCell.bChanged ),
810 bCompile( rCell.bCompile ),
811 bSubTotal( rCell.bSubTotal ),
812 bIsIterCell( false ),
813 bInChangeTrack( false ),
814 bNeedListening( false ),
815 mbNeedsNumberFormat( rCell.mbNeedsNumberFormat ),
816 mbAllowNumberFormatChange(false),
817 mbPostponedDirty(false),
820 cMatrixFlag ( rCell.cMatrixFlag ),
822 nFormatType( rCell.nFormatType ),
823 aResult( rCell.aResult ),
824 eTempGrammar( rCell.eTempGrammar),
828 pPreviousTrack(nullptr),
843 bool bCompileLater =
false;
858 adjustRangeName(pToken, rDoc, rCell.
rDocument, aPos, rCell.
aPos, bGlobalNamesToLocal);
860 adjustDBRange(pToken, rDoc, rCell.
rDocument);
907 bCompileLater = bClipMode;
913 if ( !bCompileLater && bClipMode )
921 if ( !bCompileLater )
999 pCell->
GetFormula( rBuffer, eGrammar, pContext );
1010 OSL_FAIL(
"ScFormulaCell::GetFormula: not a matrix");
1019 rBuffer.insert( 0,
'=');
1022 rBuffer.insert( 0,
'{');
1023 rBuffer.append(
'}');
1030 OUStringBuffer rBuffer( rFormula );
1032 rFormula = rBuffer.makeStringAndClear();
1037 OUStringBuffer
aBuf;
1042 ScCompiler aComp(rCxt, aPos, aCode,
false,
false, pContext);
1044 return aBuf.makeStringAndClear();
1075 OSL_FAIL(
"ScFormulaCell::GetFormula: not a matrix");
1084 aBuf.insert( 0,
'=');
1087 aBuf.insert( 0,
'{');
1091 return aBuf.makeStringAndClear();
1130 if ( bWasInFormulaTree )
1144 if ( rFormula[0] ==
'=' )
1155 if ( bWasInFormulaTree )
1165 if ( bWasInFormulaTree )
1179 if ( rFormula[0] ==
'=' )
1190 if ( bWasInFormulaTree )
1205 if ( bWasInFormulaTree )
1210 bNoListening =
true;
1222 if ( !bNoListening )
1225 if ( bWasInFormulaTree )
1245 if ( bWasInFormulaTree )
1250 bNoListening =
true;
1262 if ( !bNoListening )
1265 if ( bWasInFormulaTree )
1289 if (bWasInFormulaTree)
1293 OUString aFormula, aFormulaNmsp;
1300 bool bDoCompile =
true;
1302 if ( !
mxGroup && aFormulaNmsp.isEmpty() )
1304 ScAddress aPreviousCell( aPos );
1305 aPreviousCell.
IncRow( -1 );
1312 OUStringBuffer aShouldBeBuf;
1316 const sal_Int32 nLeadingEqual = (aFormula.getLength() > 0 && aFormula[0] ==
'=') ? 1 : 0;
1317 OUString aShouldBe = aShouldBeBuf.makeStringAndClear();
1318 if (aFormula.getLength() == aShouldBe.getLength() + nLeadingEqual &&
1319 aFormula.match( aShouldBe, nLeadingEqual))
1357 if ( !aFormula.isEmpty() && aFormula[0] ==
'=' )
1391 else if (bWasInFormulaTree)
1397 bool bNewCompiled =
false;
1405 bNewCompiled =
true;
1415 bNewCompiled =
true;
1426 OSL_FAIL(
"Formula cell INFINITY!!! Where does this document come from?");
1444 if (bStartListening)
1464 class RecursionCounter
1467 bool bStackedInIteration;
1468 #if defined DBG_UTIL && !defined NDEBUG
1474 #
if defined DBG_UTIL && !defined NDEBUG
1479 if (bStackedInIteration)
1486 if (bStackedInIteration)
1488 #if defined DBG_UTIL && !defined NDEBUG
1502 struct TemporaryCellGroupMaker
1506 , mEnabled( enable )
1508 if( mEnabled && mCell->GetCellGroup() == nullptr )
1510 mCell->CreateCellGroup( 1,
false );
1511 mCell->GetDocument().GetRecursionHelper().AddTemporaryGroupCell( mCell );
1514 ~TemporaryCellGroupMaker() COVERITY_NOEXCEPT_FALSE
1517 mCell->GetDocument().GetRecursionHelper().CleanTemporaryGroupCells();
1520 const bool mEnabled;
1528 bool bGroupInterpreted =
false;
1536 return bGroupInterpreted;
1556 return bGroupInterpreted;
1559 #if DEBUG_CALCULATION
1560 static bool bDebugCalculationInit =
true;
1561 if (bDebugCalculationInit)
1563 aDC.maTrigger = aDebugCalculationTriggerAddress;
1564 aDC.mbPrintResults =
true;
1565 bDebugCalculationInit =
false;
1567 DebugCalculationStacker aDebugEntry(aPos,
rDocument);
1571 return bGroupInterpreted;
1577 return bGroupInterpreted;
1584 return bGroupInterpreted;
1595 return bGroupInterpreted;
1602 return bGroupInterpreted;
1614 #if DEBUG_CALCULATION
1621 #if DEBUG_CALCULATION
1624 if (!bGroupInterpreted)
1631 return bGroupInterpreted;
1636 if (!bPartOfCycleBefore && bPartOfCycleAfter && rRecursionHelper.
AnyParentFGInCycle())
1639 return bGroupInterpreted;
1657 bool bIterationFromRecursion =
false;
1658 bool bResumeIteration =
false;
1664 bIterationFromRecursion || bResumeIteration)
1668 if (!bIterationFromRecursion && bResumeIteration)
1670 bResumeIteration =
false;
1672 ScFormulaRecursionList::const_iterator aOldStart(
1676 for (ScFormulaRecursionList::const_iterator aIter(
1687 sal_uInt16 nIteration = rRecursionHelper.
GetIteration();
1688 for (ScFormulaRecursionList::const_iterator aIter(
1689 aOldStart); aIter !=
1695 if (!pIterCell->
bDirty || aIter == aOldStart)
1697 pIterCell->
aResult = (*aIter).aPreviousResult;
1701 pIterCell->
bDirty =
true;
1706 bResumeIteration =
false;
1713 if (rRecursionHelper.
GetList().size() > 1)
1716 if (pLastCell !=
this)
1730 for (ScFormulaRecursionList::const_iterator aIter(
1735 pIterCell->
aResult = (*aIter).aPreviousResult;
1739 bIterationFromRecursion =
false;
1741 for ( ; rRecursionHelper.
GetIteration() <= nIterMax && !rDone;
1746 for ( ScFormulaRecursionList::iterator aIter(
1756 (*aIter).aPreviousResult = pIterCell->
aResult;
1774 bResumeIteration =
true;
1779 if (!bResumeIteration)
1783 for (ScFormulaRecursionList::const_iterator aIter(
1791 pIterCell->
bRunning = (*aIter).bOldRunning;
1796 for (ScFormulaRecursionList::const_iterator aIter(
1804 pIterCell->
bRunning = (*aIter).bOldRunning;
1836 bIterationFromRecursion =
false;
1844 for (ScFormulaRecursionList::const_iterator aIter(
1857 pCell->
bRunning = (*aIter).bOldRunning;
1864 if (!bResumeIteration)
1865 bIterationFromRecursion =
true;
1867 else if (bResumeIteration ||
1869 rRecursionHelper.
GetList().erase(
1873 rRecursionHelper.
Clear();
1875 }
while (bIterationFromRecursion || bResumeIteration);
1878 #if DEBUG_CALCULATION
1880 if (nErr != FormulaError::NONE)
1881 aDC.storeResultError( nErr);
1888 return bGroupInterpreted;
1920 std::unique_ptr<ScInterpreter> pScopedInterpreter;
1930 pInterpreter = pScopedInterpreter.get();
1944 case FormulaError::CircularReference :
1973 bool bContentChanged =
false;
1979 if( pInterpreter->
GetError() != FormulaError::NONE && pInterpreter->
GetError() != FormulaError::CircularReference)
1983 if (pInterpreter->
GetError() == FormulaError::RetryCircular)
2022 if( pInterpreter->
GetError() != nOldErrCode )
2027 bContentChanged =
true;
2056 if (bForceNumberFormat)
2060 if (nRetType == SvNumFormatType::LOGICAL)
2062 double fVal = aNewResult.GetDouble();
2063 if (fVal != 1.0 && fVal != 0.0)
2064 bForceNumberFormat =
false;
2071 case SvNumFormatType::PERCENT:
2072 case SvNumFormatType::CURRENCY:
2073 case SvNumFormatType::SCIENTIFIC:
2074 case SvNumFormatType::FRACTION:
2075 bForceNumberFormat =
false;
2077 case SvNumFormatType::NUMBER:
2079 bForceNumberFormat =
false;
2085 else if (nRetType == SvNumFormatType::TEXT)
2087 bForceNumberFormat =
false;
2089 if (bForceNumberFormat)
2096 if (nOldFormatIndex !=
2098 bForceNumberFormat =
false;
2104 bool bSetFormat =
true;
2126 StackVar eNewCellResultType = aNewResult.GetCellResultType();
2129 if (eNewCellResultType !=
svDouble)
2136 double fVal = aNewResult.GetDouble();
2137 if (fVal != 1.0 && fVal != 0.0)
2158 if (bSetFormat && (bForceNumberFormat || ((nFormatIndex % SV_COUNTRY_LANGUAGE_OFFSET) != 0)))
2191 StackVar eNew = aNewResult.GetCellResultType();
2203 bContentChanged = (eOld != eNew ||
2214 StackVar eNew = aNewResult.GetCellResultType();
2232 bContentChanged =
true;
2287 if ( pData && !pData->
IsDataValid(aTmpCell, aPos))
2296 if (pProgress && pProgress->
Enabled())
2336 OSL_ENSURE(
pCode->
GetCodeError() != FormulaError::NONE,
"no RPN code and no errors ?!?!" );
2349 std::unique_ptr<ScInterpreter> pScopedInterpreter;
2355 pInterpreter = pScopedInterpreter.get();
2396 else if (nCols || nRows)
2428 if (nHint == SfxHintId::ScReference)
2440 aPos, rRefColReorder.
getTab(),
2452 aPos, rRefRowReorder.
getTab(),
2478 if (!(nHint == SfxHintId::ScDataChanged || nHint == SfxHintId::ScTableOpDirty || (
bSubTotal && nHint == SfxHintId::ScHiddenRowsChanged)))
2481 bool bForceTrack =
false;
2482 if ( nHint == SfxHintId::ScTableOpDirty )
2512 switch (rQuery.
getId())
2519 rRefQuery.
add(aPos);
2568 mxGroup->mbPartOfCycle =
false;
2653 if ( (nBits & ScRecalcMode::EMask) != ScRecalcMode::NORMAL )
2655 if ( nBits & ScRecalcMode::ONLOAD_ONCE )
2657 nBits = (nBits & ~
ScRecalcMode::EMask) | ScRecalcMode::NORMAL;
2691 OUString aCellString;
2693 const Color* pColor;
2705 pFormatter->
GetOutputString( fValue, nCellFormat, rCellText, &pColor );
2710 pFormatter->
GetOutputString( aCellString, nCellFormat, rCellText, &pColor );
2716 if (!xMat->IsValue(0, 1))
2717 rURL = xMat->GetString(0, 1).getString();
2720 xMat->GetDouble(0, 1), nURLFormat, rURL, &pColor);
2728 pFormatter->
GetOutputString( aCellString, nURLFormat, rURL, &pColor );
2847 ScAddress aAbs = rRef.
toAbs(rDoc, aPos);
2868 static thread_local
SCCOL nC;
2869 static thread_local
SCROW nR;
2873 if ( aOrg != rOrgPos )
2885 if ( nC == 0 || nR == 0 )
2892 ScAddress aAdr( aOrg );
2928 #if OSL_DEBUG_LEVEL > 0
2929 SAL_WARN(
"sc",
"broken Matrix, no MatFormula at origin, Pos: "
2941 if ( dC >= 0 && dR >= 0 && dC < nC && dR < nR )
2956 SAL_WARN(
"sc",
"broken Matrix, Pos: "
2960 <<
", MatCols: " <<
static_cast<sal_Int32
>( nC )
2961 <<
", MatRows: " << static_cast<sal_Int32>( nR )
2962 <<
", DiffCols: " <<
static_cast<sal_Int32
>( dC )
2963 <<
", DiffRows: " << static_cast<sal_Int32>( dR ));
2980 if (nErr != FormulaError::NONE)
2988 if (nErr != FormulaError::NONE)
2998 if (rErr != FormulaError::NONE)
3009 if (nErr != FormulaError::NONE)
3018 if (nErr != FormulaError::NONE)
3059 if (pFirstReference)
3063 std::vector<formula::FormulaToken*> aReferences;
3064 aReferences.push_back(pFirstReference);
3069 if (lcl_isReference(*pToken))
3071 aReferences.push_back(pToken);
3084 && (pFunction->GetParamCount() == aReferences.size()))
3086 return lcl_refListFormsOneRange(
rDocument, aPos, aReferences, rRange);
3140 assert(!
"can't move ScFormulaCell");
3151 bool checkCompileColRowName(
3153 const ScAddress& aOldPos,
const ScAddress& aPos,
bool bValChanged)
3166 while ((t = aIter.GetNextColRowName()) !=
nullptr)
3171 ScAddress aAdr = rRef.
toAbs(rDoc, aPos);
3186 ScAddress aAdr = rRef.
toAbs(rDoc, aPos);
3205 bool bMoved = (aPos != aOldPos);
3211 for (; t; t = aIter.GetNextColRowName())
3214 ScAddress aAbs = rRef.
toAbs(rDoc, aPos);
3232 void setOldCodeToUndo(
3247 rUndoDoc, aUndoPos, pOldCode ? *pOldCode :
ScTokenArray(rUndoDoc), eTempGrammar, cMatrixFlag);
3262 bool bCellStateChanged =
false;
3263 ScAddress aUndoPos( aPos );
3265 aUndoPos = *pUndoCellPos;
3266 ScAddress aOldPos( aPos );
3271 bool bHasColRowNames =
false;
3275 bHasRefs = bHasColRowNames;
3279 if (!bHasRefs && !bOnRefMove)
3282 return bCellStateChanged;
3284 std::unique_ptr<ScTokenArray> pOldCode;
3288 bool bValChanged =
false;
3289 bool bRefModified =
false;
3302 if (bValChanged || bRefModified)
3303 bCellStateChanged =
true;
3307 bOnRefMove = (bValChanged || (aPos != aOldPos) || bRefModified);
3309 bool bNewListening =
false;
3310 bool bInDeleteUndo =
false;
3316 if (bHasColRowNames && !bRecompile)
3317 bRecompile = checkCompileColRowName(rCxt,
rDocument, *
pCode, aOldPos, aPos, bValChanged);
3320 bInDeleteUndo = (pChangeTrack && pChangeTrack->
IsInDeleteUndo());
3323 bool bHasRelName =
false;
3332 bNewListening = (bRefModified || bRecompile
3333 || (bValChanged && bInDeleteUndo) || bHasRelName);
3335 if ( bNewListening )
3340 bool bNeedDirty = (bValChanged || bRecompile || bOnRefMove);
3342 if (pUndoDoc && (bValChanged || bOnRefMove))
3352 if ( !bInDeleteUndo )
3355 if ( bNewListening )
3372 return bCellStateChanged;
3381 ScAddress aUndoPos( aPos );
3383 aUndoPos = *pUndoCellPos;
3384 ScAddress aOldPos( aPos );
3386 bool bCellInMoveTarget = rCxt.
maRange.
In(aPos);
3388 if ( bCellInMoveTarget )
3399 bool bHasColRowNames =
false;
3403 bHasRefs = bHasColRowNames;
3407 if (!bHasRefs && !bOnRefMove)
3412 bool bCellStateChanged =
false;
3413 std::unique_ptr<ScTokenArray> pOldCode;
3417 bool bValChanged =
false;
3418 bool bRefModified =
false;
3431 if (bValChanged || bRefModified)
3432 bCellStateChanged =
true;
3436 bOnRefMove = (bValChanged || (aPos != aOldPos));
3438 bool bColRowNameCompile =
false;
3439 bool bHasRelName =
false;
3440 bool bNewListening =
false;
3441 bool bInDeleteUndo =
false;
3447 if (bHasColRowNames)
3448 bColRowNameCompile = checkCompileColRowName(rCxt,
rDocument, *
pCode, aOldPos, aPos, bValChanged);
3451 bInDeleteUndo = (pChangeTrack && pChangeTrack->
IsInDeleteUndo());
3459 bNewListening = (bRefModified || bColRowNameCompile
3460 || bValChanged || bHasRelName)
3466 if ( bNewListening )
3470 bool bNeedDirty =
false;
3472 if ( bRefModified || bColRowNameCompile ||
3473 (bValChanged && bHasRelName ) || bOnRefMove)
3476 if (pUndoDoc && !bCellInMoveTarget && (bValChanged || bRefModified || bOnRefMove))
3479 bValChanged =
false;
3488 if ( !bInDeleteUndo )
3491 if ( bNewListening )
3503 return bCellStateChanged;
3512 ScAddress aUndoPos( aPos );
3514 aUndoPos = *pUndoCellPos;
3515 ScAddress aOldPos( aPos );
3529 bHasRefs = bHasRefs || bHasColRowNames;
3532 if (!bHasRefs && !bOnRefMove)
3537 std::unique_ptr<ScTokenArray> pOldCode;
3543 bOnRefMove = (aPos != aOldPos);
3545 bool bNeedDirty = bOnRefMove;
3547 if (pUndoDoc && bOnRefMove)
3615 ScAddress aOldPos =
aPos;
3645 ScAddress aOldPos =
aPos;
3670 ScAddress aOldPos =
aPos;
3728 if (nTable != rRef1.
Tab())
3730 else if (nTable != aPos.
Tab())
3738 if(nTable != rRef2.
Tab())
3740 else if (nTable != aPos.
Tab())
3751 if ( bForceIfNameInUse && !
bCompile )
3761 bool bFound =
false;
3775 nTemp = rRef1.
Col();
3781 nTemp = rRef2.
Col();
3796 ScDocument* pUndoDoc )
3800 ScAddress aOldPos =
aPos;
3801 bool bPosChanged =
false;
3803 ScRange aDestRange( rDest, ScAddress(
3807 if ( aDestRange.
In( aOldPos ) )
3814 aOldPos.
Set( nRelPosX, nRelPosY, nRelPosZ );
3818 std::unique_ptr<ScTokenArray> pOld;
3821 bool bRefChanged =
false;
3852 *pUndoDoc, aPos, pOld ? *pOld :
ScTokenArray(*pUndoDoc), eTempGrammar, cMatrixFlag);
3870 bool bRefChanged =
false;
3914 if (p->GetOpCode() ==
ocName)
3916 sal_uInt16 nTokenIndex = p->GetIndex();
3917 SCTAB nTab = p->GetSheet();
3920 if (nRecursion < 126)
3944 pCode = pNew.release();
3957 OpCode eOp = p->GetOpCode();
3994 SAL_INFO(
"sc.opencl",
"You can't create a new group if the cell is already a part of a group");
4000 mxGroup->mbInvariant = bInvariant;
4046 if ( !pThis || !pOther )
4052 if ( nThisLen != nOtherLen )
4062 bool bInvariant =
true;
4065 for ( sal_uInt16
i = 0;
i < nThisLen;
i++ )
4167 if ( !pThis || !pOther )
4173 if ( nThisLen != nOtherLen )
4176 for ( sal_uInt16
i = 0;
i < nThisLen;
i++ )
4258 int splitup(
int N,
int K,
int&
A)
4268 const int ideal_num_parts = N / K;
4269 if (ideal_num_parts * K == N)
4270 return ideal_num_parts;
4272 const int num_parts = ideal_num_parts + 1;
4273 const int nominal_part_size = N / num_parts;
4275 A = N - num_parts * nominal_part_size;
4280 struct ScDependantsCalculator
4286 const ScAddress&
mrPos;
4287 const bool mFromFirstRow;
4288 const SCROW mnStartOffset;
4289 const SCROW mnEndOffset;
4290 const SCROW mnSpanLen;
4293 const ScAddress& rPos,
bool fromFirstRow,
SCROW nStartOffset,
SCROW nEndOffset) :
4296 mxGroup(rCell.GetCellGroup()),
4297 mnLen(mxGroup->mnLength),
4302 mFromFirstRow(fromFirstRow),
4303 mnStartOffset(nStartOffset),
4304 mnEndOffset(nEndOffset),
4305 mnSpanLen(nEndOffset - nStartOffset + 1)
4315 bool isSelfReferenceRelative(
const ScAddress& rRefPos,
SCROW nRelRow)
4317 if (rRefPos.
Col() != mrPos.
Col() || rRefPos.
Tab() != mrPos.
Tab())
4320 SCROW nEndRow = mrPos.
Row() + mnLen - 1;
4324 SCROW nTest = nEndRow;
4326 if (nTest >= mrPos.
Row())
4333 if (nTest <= nEndRow)
4348 bool isSelfReferenceAbsolute(
const ScAddress& rRefPos)
4350 if (rRefPos.
Col() != mrPos.
Col() || rRefPos.
Tab() != mrPos.
Tab())
4353 SCROW nEndRow = mrPos.
Row() + mnLen - 1;
4355 if (rRefPos.
Row() < mrPos.
Row())
4359 if (rRefPos.
Row() > nEndRow && !mFromFirstRow)
4368 bool isDoubleRefSpanGroupRange(
const ScRange& rAbs,
bool bIsRef1RowRel,
bool bIsRef2RowRel)
4377 SCROW nEndRow = nStartRow + mnLen - 1;
4381 if (bIsRef1RowRel && bIsRef2RowRel &&
4382 ((nRefStartRow <= nStartRow && nRefEndRow >= nEndRow) ||
4383 ((nRefStartRow + mnLen - 1) <= nStartRow &&
4384 (nRefEndRow + mnLen - 1) >= nEndRow)))
4387 if (!bIsRef1RowRel && nRefStartRow <= nStartRow &&
4388 (nRefEndRow >= nEndRow || (nRefEndRow + mnLen - 1) >= nEndRow))
4391 if (!bIsRef2RowRel &&
4392 nRefStartRow <= nStartRow && nRefEndRow >= nEndRow)
4397 if (mFromFirstRow && nRefEndRow >= nStartRow)
4406 SCROW nLastRow = nRow + nRowLen - 1;
4408 if (nLastRow < (nRow + nRowLen - 1))
4413 nRowLen = nLastRow - nRow + 1;
4419 else if (nLastRow == 0)
4433 bool bHasSelfReferences =
false;
4438 for (sal_Int32 nTokenIdx = nCodeLen-1; nTokenIdx >= 0; --nTokenIdx)
4440 auto p = pRPNArray[nTokenIdx];
4441 if (!bInDocShellRecalc)
4449 OpCode nOpCode = p->GetOpCode();
4450 if (nOpCode == ocIf || nOpCode == ocIfs_MS || nOpCode == ocSwitch_MS)
4454 switch (p->GetType())
4461 ScAddress aRefPos = aRef.
toAbs(mrDoc, mrPos);
4468 if (isSelfReferenceRelative(aRefPos, aRef.
Row()))
4470 bHasSelfReferences =
true;
4475 SCROW nTrimLen = trimLength(aRefPos.
Tab(), aRefPos.
Col(), aRefPos.
Col(), aRefPos.
Row() + mnStartOffset, mnSpanLen);
4478 aRefPos.
Col(), aRefPos.
Row() + mnStartOffset + nTrimLen - 1, aRefPos.
Tab()));
4482 if (isSelfReferenceAbsolute(aRefPos))
4484 bHasSelfReferences =
true;
4509 bHasSelfReferences =
true;
4513 else if (isSelfReferenceAbsolute(aAbs.
aStart))
4515 bHasSelfReferences =
true;
4522 if (isSelfReferenceRelative(aAbs.
aEnd, aRef.
Ref2.
Row()))
4524 bHasSelfReferences =
true;
4528 else if (isSelfReferenceAbsolute(aAbs.
aEnd))
4530 bHasSelfReferences =
true;
4534 if (isDoubleRefSpanGroupRange(aAbs, bIsRef1RowRel, bIsRef2RowRel))
4536 bHasSelfReferences =
true;
4545 SCROW nArrayLength = nLastRefRow - nFirstRefRow + 1;
4546 assert(nArrayLength > 0);
4552 aAbs.
aEnd.
Col(), nFirstRefRow + nArrayLength - 1, aAbs.
aEnd.
Tab()));
4563 for (
size_t i = 0;
i < aRangeList.
size(); ++
i)
4565 const ScRange & rRange = aRangeList[
i];
4573 nLength += nStartRow;
4582 if (bHasSelfReferences)
4583 mxGroup->mbPartOfCycle =
true;
4585 return !bHasSelfReferences;
4593 if (!mxGroup || !
pCode)
4599 if (mxGroup->mbPartOfCycle)
4601 aScope.addMessage(
"This formula-group is part of a cycle");
4607 aScope.addMessage(
"group calc disabled");
4619 aScope.addGroupSizeThresholdMessage(*
this);
4626 aScope.addMessage(
"matrix skipped");
4640 aScope.addMessage(
"cell not in document");
4649 RecursionCounter aRecursionCounter( rRecursionHelper,
this);
4651 bool bDependencyComputed =
false;
4652 bool bDependencyCheckFailed =
false;
4655 SCROW nMaxOffset = mxGroup->mnLength - 1;
4656 nStartOffset = nStartOffset < 0 ? 0 : std::min(nStartOffset, nMaxOffset);
4657 nEndOffset = nEndOffset < 0 ? nMaxOffset : std::min(nEndOffset, nMaxOffset);
4659 if (nEndOffset < nStartOffset)
4662 nEndOffset = nMaxOffset;
4678 bool bCalcDependencyOnly)
4684 if (bCalcDependencyOnly)
4690 ScDependantsCalculator aCalculator(
rDocument, *
pCode, *
this, mxGroup->mpTopCell->aPos, fromFirstRow, nStartOffset, nEndOffset);
4691 return aCalculator.DoIt();
4694 bool bOKToParallelize =
false;
4697 if (mxGroup->mbPartOfCycle)
4700 rScope.
addMessage(
"found circular formula-group dependencies");
4705 ScDependantsCalculator aCalculator(
rDocument, *
pCode, *
this, mxGroup->mpTopCell->aPos, fromFirstRow, nStartOffset, nEndOffset);
4706 bOKToParallelize = aCalculator.DoIt();
4713 rScope.
addMessage(
"Recursion limit reached, cannot thread this formula group now");
4717 if (mxGroup->mbPartOfCycle)
4720 rScope.
addMessage(
"found circular formula-group dependencies");
4728 rScope.
addMessage(
"multi-group-dependency failed");
4732 if (!bOKToParallelize)
4735 rScope.
addMessage(
"could not do new dependencies calculation thing");
4744 std::map<SCCOL, ScFormulaCell*>& rFGMap,
bool bLeft)
4746 const SCROW nLen = xGroup->mnLength;
4747 const sal_Int32 nWt = xGroup->mnWeight;
4748 ScAddress aAddr(xGroup->mpTopCell->aPos);
4758 while (nColRet >= 0 && nColRet <= nMaxCol)
4775 if (xNGroup->mpTopCell->aPos.Row() != aAddr.
Row())
4778 const SCROW nNLen = xNGroup->mnLength;
4779 const sal_Int32 nNWt = pCell->
GetWeight();
4780 if (nNLen != nLen || nNWt != nWt)
4783 rFGSet.
insert(xNGroup.get());
4784 rFGMap[nColRet] = xNGroup->mpTopCell;
4802 bool& bDependencyComputed,
4803 bool& bDependencyCheckFailed,
4807 static const bool bThreadingProhibited = std::getenv(
"SC_NO_THREADED_CALCULATION");
4808 if (!bDependencyCheckFailed && !bThreadingProhibited &&
4814 bDependencyComputed =
true;
4815 bDependencyCheckFailed =
true;
4819 bDependencyComputed =
true;
4828 const unsigned mnThisThread;
4829 const unsigned mnThreadsTotal;
4830 ScDocument* mpDocument;
4832 const ScAddress& mrTopPos;
4835 SCROW mnStartOffset;
4839 Executor(
const std::shared_ptr<comphelper::ThreadTaskTag>& rTag,
4840 unsigned nThisThread,
4841 unsigned nThreadsTotal,
4842 ScDocument* pDocument2,
4844 const ScAddress& rTopPos,
4850 mnThisThread(nThisThread),
4851 mnThreadsTotal(nThreadsTotal),
4852 mpDocument(pDocument2),
4853 mpContext(pContext),
4855 mnStartCol(nStartCol),
4857 mnStartOffset(nStartOff),
4858 mnEndOffset(nEndOff)
4862 virtual void doWork()
override
4864 ScRange aCalcRange(mnStartCol, mrTopPos.
Row() + mnStartOffset, mrTopPos.
Tab(),
4865 mnEndCol, mrTopPos.
Row() + mnEndOffset, mrTopPos.
Tab());
4876 if ( bHyperThreadingActive && nThreadCount >= 2 )
4879 SAL_INFO(
"sc.threaded",
"Running " << nThreadCount <<
" threads");
4882 std::map<SCCOL, ScFormulaCell*> aFGMap;
4883 aFGSet.
insert(mxGroup.get());
4887 SCCOL nColEnd = nColStart;
4894 if (nColStart != nColEnd)
4897 for (
SCCOL nCurrCol = nColStart; nCurrCol <= nColEnd; ++nCurrCol)
4899 if (nCurrCol == aPos.
Col())
4902 bool bFGOK = aFGMap[nCurrCol]->CheckComputeDependencies(aScope,
false, nStartOffset, nEndOffset,
true);
4905 nColEnd = nColStart = aPos.
Col();
4911 std::vector<std::unique_ptr<ScInterpreter>> aInterpreters(nThreadCount);
4923 for (
int i = 0;
i < nThreadCount; ++
i)
4930 rThreadPool.
pushTask(std::make_unique<Executor>(aTag,
i, nThreadCount, &
rDocument, context, mxGroup->mpTopCell->aPos,
4931 nColStart, nColEnd, nStartOffset, nEndOffset));
4934 SAL_INFO(
"sc.threaded",
"Waiting for threads to finish work");
4941 for (
int i = 0;
i < nThreadCount; ++
i)
4952 ScAddress aStartPos(mxGroup->mpTopCell->aPos);
4953 SCROW nSpanLen = nEndOffset - nStartOffset + 1;
4954 aStartPos.
SetRow(aStartPos.
Row() + nStartOffset);
4957 aStartPos.
Tab(), aInterpreters[0].get());
4967 bool& bDependencyComputed,
4968 bool& bDependencyCheckFailed)
4979 aScope.
addMessage(
"group calc disabled due to vector state (non-vector-supporting opcode)");
4982 aScope.
addMessage(
"group calc disabled due to vector state (non-vector-supporting stack variable)");
4985 aScope.
addMessage(
"group calc disabled due to vector state (opcode not in subset)");
4990 aScope.
addMessage(
"group calc disabled due to vector state (unknown)");
5007 if (bDependencyCheckFailed)
5012 bDependencyComputed =
true;
5013 bDependencyCheckFailed =
true;
5017 bDependencyComputed =
true;
5021 if (mxGroup->mbInvariant &&
false)
5024 int nMaxGroupLength = INT_MAX;
5031 nMaxGroupLength = 1000;
5034 if (std::getenv(
"SC_MAX_GROUP_LENGTH"))
5035 nMaxGroupLength = std::atoi(std::getenv(
"SC_MAX_GROUP_LENGTH"));
5038 const int nNumParts = splitup(
GetSharedLength(), nMaxGroupLength, nNumOnePlus);
5042 ScAddress aOrigPos = mxGroup->mpTopCell->aPos;
5043 for (
int i = 0;
i < nNumParts;
i++, nOffset += nCurChunkSize)
5055 xGroup->mpTopCell = mxGroup->mpTopCell;
5056 xGroup->mpTopCell->aPos = aOrigPos;
5057 xGroup->mpTopCell->aPos.
IncRow(nOffset);
5058 xGroup->mbInvariant = mxGroup->mbInvariant;
5059 xGroup->mnLength = nCurChunkSize;
5060 xGroup->mpCode = std::move(mxGroup->mpCode);
5072 SAL_INFO(
"sc.opencl",
"group " << xGroup->mpTopCell->aPos <<
" has unhandled implicit intersections, disabling");
5076 SAL_INFO(
"sc.opencl",
"unhandled implicit intersection opcode "
5078 <<
"(" <<
int(opcode) <<
")");
5083 SAL_INFO(
"sc.opencl",
"conversion of group " << xGroup->mpTopCell->aPos <<
" failed, disabling");
5090 mxGroup->mpTopCell->aPos = aOrigPos;
5091 xGroup->mpTopCell =
nullptr;
5092 mxGroup->mpCode = std::move(xGroup->mpCode);
5095 aScope.
addMessage(
"group token conversion failed");
5104 if (pInterpreter ==
nullptr ||