diff options
author | Tor Lillqvist <tml@collabora.com> | 2017-08-30 09:28:59 +0300 |
---|---|---|
committer | Dennis Francis <dennis.francis@collabora.co.uk> | 2017-11-21 13:49:50 +0530 |
commit | 8f04d760ec79f753e134f9fc6796680a6f7daa88 (patch) | |
tree | 71dddc6441e83fd049ff07bf85711f766e21b76c | |
parent | 16fb61d9897c76eb4f4e7e4fcf90912c4c65073f (diff) |
More work on the ScDependantsCalculator
Might now actually do what it should.
Change-Id: Ibf38560a37910924c4fade79cbbf4553d6dbd077
-rw-r--r-- | sc/source/core/data/column2.cxx | 35 | ||||
-rw-r--r-- | sc/source/core/data/formulacell.cxx | 142 |
2 files changed, 124 insertions, 53 deletions
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index 77ff00d5018d..0178d7664197 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -2614,27 +2614,6 @@ copyFirstFormulaBlock( return rCxt.setCachedColArray(nTab, nCol, pNumArray, pStrArray); } -bool -DoFormulaBlockForParallelism( const sc::CellStoreType::iterator& itBlk ) -{ - sc::formula_block::iterator it = sc::formula_block::begin(*itBlk->data); - sc::formula_block::iterator itEnd; - - itEnd = it; - std::advance(itEnd, itBlk->size); - for (; it != itEnd; ++it) - { - ScFormulaCell& rFC = **it; - sc::FormulaResultValue aRes = rFC.GetResult(); - if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError != FormulaError::NONE) - { - return false; - } - } - - return true; -} - struct NonNullStringFinder { bool operator() (const rtl_uString* p) const { return p != nullptr; } @@ -2832,17 +2811,11 @@ bool ScColumn::HandleRefArrayForParallelism( SCROW nRow1, SCROW nRow2 ) if (nRow1 > nRow2) return false; - for (auto itBlk = maCells.begin(); itBlk != maCells.end(); ++itBlk) + for (auto i = nRow1; i <= nRow2; ++i) { - switch (itBlk->type) - { - case sc::element_type_formula: - { - if (!DoFormulaBlockForParallelism( itBlk)) - return false; - return true; - } - } + auto aCell = GetCellValue(i); + if (aCell.meType == CELLTYPE_FORMULA) + aCell.mpFormula->MaybeInterpret(); } return true; diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index fbcd67cd7798..909bca982447 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -37,6 +37,7 @@ #include <recursionhelper.hxx> #include <docoptio.hxx> #include <rangenam.hxx> +#include <rangelst.hxx> #include <dbdata.hxx> #include <progress.hxx> #include <scmatrix.hxx> @@ -4096,26 +4097,29 @@ int splitup(int N, int K, int& A) struct ScDependantsCalculator { ScDocument& mrDoc; - ScTokenArray& mrCode; - ScFormulaCell& mrCell; + const ScTokenArray& mrCode; + const SCROW mnLen; const ScAddress& mrPos; - ScDependantsCalculator(ScDocument& rDoc, ScTokenArray& rCode, ScFormulaCell& rCell, const ScAddress& rPos) : + ScDependantsCalculator(ScDocument& rDoc, const ScTokenArray& rCode, const ScFormulaCell& rCell, const ScAddress& rPos) : mrDoc(rDoc), mrCode(rCode), - mrCell(rCell), + mnLen(rCell.GetCellGroup()->mnLength), mrPos(rPos) { } // FIXME: copy-pasted from ScGroupTokenConverter. factor out somewhere else - bool cellIsSelfReferenceRelative(const ScAddress& rRefPos, SCROW nRelRow) + + // I think what this function does is to check whether the relative row reference nRelRow points + // to a row that is inside the range of rows covered by the formula group. + + bool isSelfReferenceRelative(const ScAddress& rRefPos, SCROW nRelRow) { if (rRefPos.Col() != mrPos.Col()) return false; - SCROW nLen = mrCell.GetCellGroup()->mnLength; - SCROW nEndRow = mrPos.Row() + nLen - 1; + SCROW nEndRow = mrPos.Row() + mnLen - 1; if (nRelRow < 0) { @@ -4136,6 +4140,27 @@ struct ScDependantsCalculator } // FIXME: another copy-paste + + // And this correspondingly checks whether an absolute row is inside the range of rows covered + // by the formula group. + + bool isSelfReferenceAbsolute(const ScAddress& rRefPos) + { + if (rRefPos.Col() != mrPos.Col()) + return false; + + SCROW nEndRow = mrPos.Row() + mnLen - 1; + + if (rRefPos.Row() < mrPos.Row()) + return false; + + if (rRefPos.Row() > nEndRow) + return false; + + return true; + } + + // FIXME: another copy-paste SCROW trimLength(SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCROW nRowLen) { SCROW nLastRow = nRow + nRowLen - 1; // current last row. @@ -4147,12 +4172,9 @@ struct ScDependantsCalculator // surrounding conditions changed? nRowLen = nLastRow - nRow + 1; // Anyway, let's assume it doesn't make sense to return a - // negative value here. But should we then return 0 or 1? In - // the "Column is empty" case below, we return 1, why!? And, - // at the callsites there are tests for a zero value returned - // from this function (but not for a negative one). - if (nRowLen < 0) - nRowLen = 0; + // negative or zero value here. + if (nRowLen <= 0) + nRowLen = 1; } else if (nLastRow == 0) // Column is empty. @@ -4163,39 +4185,115 @@ struct ScDependantsCalculator bool DoIt() { -// from ScGroupTokenConverter::convert in sc/source/core/data/grouptokenconverter.cxx + // Partially from ScGroupTokenConverter::convert in sc/source/core/data/grouptokenconverter.cxx + + ScRangeList aRangeList; for (auto p: mrCode.Tokens()) { - SCROW nLen = mrCell.GetCellGroup()->mnLength; switch (p->GetType()) { case svSingleRef: { ScSingleRefData aRef = *p->GetSingleRef(); // =Sheet1!A1 ScAddress aRefPos = aRef.toAbs(mrPos); + + if (!mrDoc.TableExists(aRefPos.Tab())) + return false; // or true? + if (aRef.IsRowRel()) { - if (cellIsSelfReferenceRelative(aRefPos, aRef.Row())) + if (isSelfReferenceRelative(aRefPos, aRef.Row())) return false; // Trim data array length to actual data range. - SCROW nTrimLen = trimLength(aRefPos.Tab(), aRefPos.Col(), aRefPos.Col(), aRefPos.Row(), nLen); + SCROW nTrimLen = trimLength(aRefPos.Tab(), aRefPos.Col(), aRefPos.Col(), aRefPos.Row(), mnLen); // Fetch double array guarantees that the length of the // returned array equals or greater than the requested // length. - if (mrDoc.TableExists(aRefPos.Tab()) && nTrimLen) - { - if (!mrDoc.HandleRefArrayForParallelism(aRefPos, nTrimLen)) - return false; - } + formula::VectorRefArray aArray; + if (nTrimLen) + aArray = mrDoc.FetchVectorRefArray(aRefPos, nTrimLen); + + if (!aArray.isValid()) + return false; + + aRangeList.Join(ScRange(aRefPos.Col(), aRefPos.Row(), aRefPos.Tab(), + aRefPos.Col(), aRefPos.Row() + nTrimLen - 1, aRefPos.Tab())); } + else + { + if (isSelfReferenceAbsolute(aRefPos)) + return false; + + aRangeList.Join(ScRange(aRefPos.Col(), aRefPos.Row(), aRefPos.Tab())); + } + } + break; + case svDoubleRef: + { + ScComplexRefData aRef = *p->GetDoubleRef(); + ScRange aAbs = aRef.toAbs(mrPos); + + // Multiple sheet + if (aRef.Ref1.Tab() != aRef.Ref2.Tab()) + return false; + + // Check for self reference. + if (aRef.Ref1.IsRowRel()) + { + if (isSelfReferenceRelative(aAbs.aStart, aRef.Ref1.Row())) + return false; + } + else if (isSelfReferenceAbsolute(aAbs.aStart)) + return false; + + if (aRef.Ref2.IsRowRel()) + { + if (isSelfReferenceRelative(aAbs.aEnd, aRef.Ref2.Row())) + return false; + } + else if (isSelfReferenceAbsolute(aAbs.aEnd)) + return false; + + // Row reference is relative. + bool bAbsLast = !aRef.Ref2.IsRowRel(); + ScAddress aRefPos = aAbs.aStart; + SCROW nRefRowSize = aAbs.aEnd.Row() - aAbs.aStart.Row() + 1; + SCROW nArrayLength = nRefRowSize; + if (!bAbsLast) + { + // range end position is relative. Extend the array length. + SCROW nLastRefRowOffset = aAbs.aEnd.Row() - mrPos.Row(); + SCROW nLastRefRow = mrPos.Row() + mnLen - 1 + nLastRefRowOffset; + SCROW nNewLength = nLastRefRow - aAbs.aStart.Row() + 1; + if (nNewLength > nArrayLength) + nArrayLength = nNewLength; + } + + // Trim trailing empty rows. + nArrayLength = trimLength(aRefPos.Tab(), aAbs.aStart.Col(), aAbs.aEnd.Col(), aRefPos.Row(), nArrayLength); + + aRangeList.Join(ScRange(aAbs.aStart.Col(), aRefPos.Row(), aRefPos.Tab(), + aAbs.aEnd.Col(), aRefPos.Row() + nArrayLength - 1, aRefPos.Tab())); } break; default: break; } } + + for (size_t i = 0; i < aRangeList.size(); ++i) + { + const ScRange* pRange = aRangeList[i]; + assert(pRange->aStart.Tab() == pRange->aEnd.Tab()); + for (auto nCol = pRange->aStart.Col(); nCol <= pRange->aEnd.Col(); nCol++) + { + if (!mrDoc.HandleRefArrayForParallelism(ScAddress(nCol, pRange->aStart.Row(), pRange->aStart.Tab()), + pRange->aEnd.Row() - pRange->aStart.Row() + 1)) + return false; + } + } return true; } }; |