sc/inc/formulacell.hxx | 11 ++++++-- sc/inc/types.hxx | 7 +++++ sc/source/core/data/column2.cxx | 20 ++++++++++++--- sc/source/core/data/formulacell.cxx | 46 ++++++++++++++++++++++++++++------- sc/source/core/tool/formulagroup.cxx | 10 +++---- 5 files changed, 75 insertions(+), 19 deletions(-)
New commits: commit c205ba358f11b2a8997c980b554a20518cdf761a Author: Kohei Yoshida <[email protected]> Date: Tue Jul 2 22:10:25 2013 -0400 Detect circular dependency in formula groups to fallback to cell-based. Change-Id: Icfb4fd4be4e0c1f6f450fb8ddce57c7b79568e6f diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index 52a1474..07b726a 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -24,6 +24,7 @@ #include "formula/tokenarray.hxx" #include "svl/listener.hxx" +#include "types.hxx" #include <set> @@ -40,19 +41,23 @@ struct ScSimilarFormulaDelta; struct SC_DLLPUBLIC ScFormulaCellGroup { - sal_Int32 mnRefCount; + mutable size_t mnRefCount; + SCROW mnStart; // Start offset of that cell SCROW mnLength; // How many of these do we have ? bool mbInvariant; + sc::GroupCalcState meCalcState; ScFormulaCellGroup(); ~ScFormulaCellGroup(); }; -inline void intrusive_ptr_add_ref(ScFormulaCellGroup *p) + +inline void intrusive_ptr_add_ref(const ScFormulaCellGroup *p) { p->mnRefCount++; } -inline void intrusive_ptr_release(ScFormulaCellGroup *p) + +inline void intrusive_ptr_release(const ScFormulaCellGroup *p) { if( --p->mnRefCount == 0 ) delete p; diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx index 487afcd..3879e99 100644 --- a/sc/inc/types.hxx +++ b/sc/inc/types.hxx @@ -54,6 +54,13 @@ const sal_uInt16 MatrixEdgeTop = 8; const sal_uInt16 MatrixEdgeRight = 16; const sal_uInt16 MatrixEdgeOpen = 32; +enum GroupCalcState +{ + GroupCalcEnabled, + GroupCalcRunning, + GroupCalcDisabled +}; + } #endif diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index 4becbb7..82daadf 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -2166,10 +2166,15 @@ bool appendDouble( nLenRemain = 0; } + sal_uInt16 nErr; + double fVal; for (; itData != itDataEnd; ++itData) { ScFormulaCell& rFC = **itData; - rArray.push_back(rFC.GetValue()); + if (!rFC.GetErrorOrValue(nErr, fVal) || nErr) + return false; + + rArray.push_back(fVal); } } break; @@ -2238,6 +2243,9 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n break; case sc::element_type_formula: { + sal_uInt16 nErr; + double fVal; + rCxt.maArrays.push_back(new sc::FormulaGroupContext::DoubleArrayType); sc::FormulaGroupContext::DoubleArrayType& rArray = rCxt.maArrays.back(); rArray.reserve(nLenRequested); @@ -2252,7 +2260,10 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n for (; it != itEnd; ++it) { ScFormulaCell& rCell = **it; - rArray.push_back(rCell.GetValue()); // the cell may be interpreted. + if (!rCell.GetErrorOrValue(nErr, fVal) || nErr) + return NULL; + + rArray.push_back(fVal); } return &rArray[0]; @@ -2264,7 +2275,10 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n for (; it != itEnd; ++it) { ScFormulaCell& rCell = **it; - rArray.push_back(rCell.GetValue()); // the cell may be interpreted. + if (!rCell.GetErrorOrValue(nErr, fVal) || nErr) + return NULL; + + rArray.push_back(fVal); } // Fill the remaining array with values from the following blocks. diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index a129726..132ed5c 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -382,7 +382,11 @@ void adjustDBRange(ScToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldD } ScFormulaCellGroup::ScFormulaCellGroup() : - mnRefCount(0), mnStart(0), mnLength(0), mbInvariant(false) + mnRefCount(0), + mnStart(0), + mnLength(0), + mbInvariant(false), + meCalcState(sc::GroupCalcEnabled) { } @@ -1547,6 +1551,9 @@ void ScFormulaCell::SetDirty( bool bDirtyFlag ) void ScFormulaCell::SetDirtyVar() { bDirty = true; + if (xGroup) + xGroup->meCalcState = sc::GroupCalcEnabled; + // mark the sheet of this cell to be calculated //#FIXME do we need to revert this remnant of old fake vba events? pDocument->AddCalculateTable( aPos.Tab() ); } @@ -1611,7 +1618,7 @@ void ScFormulaCell::SetErrCode( sal_uInt16 n ) void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits ) { if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL ) - bDirty = true; + SetDirtyVar(); if ( nBits & RECALCMODE_ONLOAD_ONCE ) { // OnLoadOnce nur zum Dirty setzen nach Filter-Import nBits = (nBits & ~RECALCMODE_EMASK) | RECALCMODE_NORMAL; @@ -2959,9 +2966,10 @@ class GroupTokenConverter ScTokenArray& mrGroupTokens; ScDocument& mrDoc; ScFormulaCell& mrCell; + const ScAddress& mrPos; public: - GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell) : - mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell) {} + GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) : + mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos) {} bool convert(ScTokenArray& rCode) { @@ -2979,8 +2987,7 @@ public: case svSingleRef: { ScSingleRefData aRef = pToken->GetSingleRef(); - aRef.CalcAbsIfRel(mrCell.aPos); - ScAddress aRefPos(aRef.nCol, aRef.nRow, aRef.nTab); + ScAddress aRefPos = aRef.toAbs(mrPos); if (aRef.IsRowRel()) { // Fetch double array guarantees that the length of the @@ -3108,6 +3115,13 @@ bool ScFormulaCell::InterpretFormulaGroup() if (!xGroup || !pCode) return false; + fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: calc state = %d\n", xGroup->meCalcState); + if (xGroup->meCalcState == sc::GroupCalcDisabled) + { + fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: group calc disabled.\n"); + return false; + } + switch (pCode->GetVectorState()) { case FormulaVectorEnabled: @@ -3126,10 +3140,26 @@ bool ScFormulaCell::InterpretFormulaGroup() sc::FormulaGroupContext aCxt; ScTokenArray aCode; - GroupTokenConverter aConverter(aCxt, aCode, *pDocument, *this); + ScAddress aTopPos = aPos; + aTopPos.SetRow(xGroup->mnStart); + GroupTokenConverter aConverter(aCxt, aCode, *pDocument, *this, aTopPos); if (!aConverter.convert(*pCode)) + { + fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: disabling group calc due to failed conversion\n"); + xGroup->meCalcState = sc::GroupCalcDisabled; + return false; + } + + xGroup->meCalcState = sc::GroupCalcRunning; + if (!sc::FormulaGroupInterpreter::getStatic()->interpret(*pDocument, aTopPos, xGroup, aCode)) + { + fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: disabling group calc due to failed calculation\n"); + xGroup->meCalcState = sc::GroupCalcDisabled; return false; - return sc::FormulaGroupInterpreter::getStatic()->interpret(*pDocument, aPos, xGroup, aCode); + } + + xGroup->meCalcState = sc::GroupCalcEnabled; + return true; } bool ScFormulaCell::InterpretInvariantFormulaGroup() diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index 79621ea..b20b437 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -33,18 +33,14 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres { // Decompose the group into individual cells and calculate them individually. - // Always set the top row to be the top of the group. Grouped formula - // cells are to be calculated for its full segment at all times. - - ScAddress aTopPos = rTopPos; - aTopPos.SetRow(xGroup->mnStart); - ScAddress aTmpPos = aTopPos; + // The caller must ensure that the top position is the start position of + // the group. + ScAddress aTmpPos = rTopPos; std::vector<double> aResults; aResults.reserve(xGroup->mnLength); - for (SCROW i = 0; i < xGroup->mnLength; ++i) + for (SCROW i = 0; i < xGroup->mnLength; ++i, aTmpPos.IncRow()) { - aTmpPos.SetRow(aTopPos.Row() + i); ScTokenArray aCode2; for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next()) { @@ -103,7 +99,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres } // for loop end (xGroup->mnLength) if (!aResults.empty()) - rDoc.SetFormulaResults(aTopPos, &aResults[0], aResults.size()); + rDoc.SetFormulaResults(rTopPos, &aResults[0], aResults.size()); return true; } commit 2af919dac0a267a55e967ff15fd2299ca0427e47 Author: Kohei Yoshida <[email protected]> Date: Tue Jul 2 18:55:29 2013 -0400 Actually we need to reset the top row to be the top of the group. To ensure that a group of formula cells are either all clean or all dirty at any given time. We'll fallback to non-grouped calculation mode if that's not possible. Change-Id: I8a5d4740571ca149d32a4630555e3c213c222ef3 diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index 3dd43e3..79621ea 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -33,14 +33,18 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres { // Decompose the group into individual cells and calculate them individually. - ScAddress aTmpPos = rTopPos; - SCROW nOffset = rTopPos.Row() - xGroup->mnStart; - SCROW nLength = xGroup->mnLength - nOffset; + // Always set the top row to be the top of the group. Grouped formula + // cells are to be calculated for its full segment at all times. + + ScAddress aTopPos = rTopPos; + aTopPos.SetRow(xGroup->mnStart); + ScAddress aTmpPos = aTopPos; + std::vector<double> aResults; - aResults.reserve(nLength); - for (SCROW i = 0; i < nLength; ++i) + aResults.reserve(xGroup->mnLength); + for (SCROW i = 0; i < xGroup->mnLength; ++i) { - aTmpPos.SetRow(rTopPos.Row() + i); + aTmpPos.SetRow(aTopPos.Row() + i); ScTokenArray aCode2; for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next()) { @@ -99,7 +103,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres } // for loop end (xGroup->mnLength) if (!aResults.empty()) - rDoc.SetFormulaResults(rTopPos, &aResults[0], aResults.size()); + rDoc.SetFormulaResults(aTopPos, &aResults[0], aResults.size()); return true; } _______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
