sc/source/core/data/column2.cxx | 50 ++----- sc/source/core/data/formulacell.cxx | 246 +++++++++++++++++++++--------------- 2 files changed, 166 insertions(+), 130 deletions(-)
New commits: commit f8f3e2e1a811e2a95147146463a0f64c83f9890e Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Tue Jun 4 01:01:02 2013 -0400 Expand shared formula tokens from Excel (which are basically range names). Also, use a better way to fetch a double array. Change-Id: I65a5bb9c972620f63e79a84b461245cc7fea1a51 diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index fcf21b0..603b486 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -1818,43 +1818,29 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& /*rCxt*/, SCR if (nRow1 > nRow2) return NULL; - ColDoubleEntry aBound; - aBound.mnStart = nRow1; - std::vector<ColDoubleEntry*>::const_iterator it = - std::lower_bound(maDoubles.begin(), maDoubles.end(), &aBound, ColDoubleEntry::LessByPtr()); - - if (it == maDoubles.end()) - return NULL; - - // There should never be an entry with empty double array. So we don't - // even bother checking for emptiness here. - - const ColDoubleEntry& rEntry = **it; - - if (rEntry.mnStart == nRow1) + std::vector<ColDoubleEntry*>::const_iterator it = maDoubles.begin(), itEnd = maDoubles.end(); + size_t nOffset = 0; + for (; it != itEnd; ++it) { - SCROW nLastRow = rEntry.mnStart + rEntry.maData.size() - 1; - if (nLastRow < nRow2) - // Array is shorter than requested length. - return NULL; - - return &rEntry.maData[0]; + const ColDoubleEntry& rEntry = **it; + SCROW nRowStart = rEntry.mnStart; + SCROW nRowEnd = nRowStart + rEntry.maData.size() - 1; + if (nRowStart <= nRow1 && nRow2 <= nRowEnd) + { + // Found it. + nOffset = nRow1 - nRowStart; + break; + } } - OSL_ASSERT(nRow1 < rEntry.mnStart); - - if (it == maDoubles.begin()) - // This is the very first array entry. - return NULL; - - --it; // Go to previous array so that rEntry.mnStart < nRow1. - OSL_ASSERT((**it).mnStart < nRow1); - SCROW nLastRow = rEntry.mnStart + rEntry.maData.size() - 1; - if (nLastRow < nRow2) - // Array is shorter than requested length. + if (it == itEnd) + { + // Array not found. return NULL; + } - return &rEntry.maData[nRow1 - rEntry.mnStart]; + const ColDoubleEntry& rEntry = **it; + return &rEntry.maData[0] + nOffset; } ScRefCellValue ScColumn::GetRefCellValue( SCROW nRow ) diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index b0ab6ff..fbc66ca 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -3059,6 +3059,32 @@ public: } } break; + case svIndex: + { + // Named range. + ScRangeName* pNames = mrDoc.GetRangeName(); + if (!pNames) + // This should never fail. + return false; + + ScRangeData* pRange = pNames->findByIndex(p->GetIndex()); + if (!pRange) + // No named range exists by that index. + return false; + + ScTokenArray* pNamedTokens = pRange->GetCode(); + if (!pNamedTokens) + // This named range is empty. + return false; + + mrGroupTokens.AddOpCode(ocOpen); + + if (!convert(*pNamedTokens)) + return false; + + mrGroupTokens.AddOpCode(ocClose); + } + break; default: mrGroupTokens.AddToken(*pToken); } commit 647a1ce3590a7c6ba5bb747d2ce7b0f5b0a600fa Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Mon Jun 3 23:47:13 2013 -0400 Extract the group token conversion loop out into a separate class. Change-Id: I790db61d2a60cf4074fd2e3291ec42f0a4649b9e diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 98df69a..b0ab6ff 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -2951,6 +2951,125 @@ ScFormulaCell::CompareState ScFormulaCell::CompareByTokenArray( ScFormulaCell *p return bInvariant ? EqualInvariant : EqualRelativeRef; } +namespace { + +class GroupTokenConverter +{ + sc::FormulaGroupContext maCxt; + ScTokenArray& mrGroupTokens; + ScDocument& mrDoc; + ScFormulaCell& mrCell; +public: + GroupTokenConverter(ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell) : + mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell) {} + + bool convert(ScTokenArray& rCode) + { + rCode.Reset(); + for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next()) + { + // A reference can be either absolute or relative. If it's absolute, + // convert it to a static value token. If relative, convert it to a + // vector reference token. Note: we only care about relative vs + // absolute reference state for row directions. + + const ScToken* pToken = static_cast<const ScToken*>(p); + switch (pToken->GetType()) + { + case svSingleRef: + { + ScSingleRefData aRef = pToken->GetSingleRef(); + aRef.CalcAbsIfRel(mrCell.aPos); + ScAddress aRefPos(aRef.nCol, aRef.nRow, aRef.nTab); + if (aRef.IsRowRel()) + { + // Fetch double array guarantees that the length of the + // returned array equals or greater than the requested + // length. + + // TODO: For now, it returns an array pointer only when + // the entire array is in contiguous memory space. Once + // we finish cell storage rework, we'll support temporary + // generation of a double array which is a combination of + // multiple cell array segments. + const double* pArray = mrDoc.FetchDoubleArray(maCxt, aRefPos, mrCell.GetCellGroup()->mnLength); + if (!pArray) + return false; + + formula::SingleVectorRefToken aTok(pArray, mrCell.GetCellGroup()->mnLength); + mrGroupTokens.AddToken(aTok); + } + else + { + // Absolute row reference. + formula::FormulaTokenRef pNewToken = mrDoc.ResolveStaticReference(aRefPos); + if (!pNewToken) + return false; + + mrGroupTokens.AddToken(*pNewToken); + } + } + break; + case svDoubleRef: + { + ScComplexRefData aRef = pToken->GetDoubleRef(); + aRef.CalcAbsIfRel(mrCell.aPos); + if (aRef.Ref1.IsRowRel() || aRef.Ref2.IsRowRel()) + { + // Row reference is relative. + bool bAbsFirst = !aRef.Ref1.IsRowRel(); + bool bAbsLast = !aRef.Ref2.IsRowRel(); + ScAddress aRefPos(aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab); + size_t nCols = aRef.Ref2.nCol - aRef.Ref1.nCol + 1; + std::vector<const double*> aArrays; + aArrays.reserve(nCols); + SCROW nArrayLength = mrCell.GetCellGroup()->mnLength; + SCROW nRefRowSize = aRef.Ref2.nRow - aRef.Ref1.nRow + 1; + if (!bAbsLast) + { + // range end position is relative. Extend the array length. + nArrayLength += nRefRowSize - 1; + } + + for (SCCOL i = aRef.Ref1.nCol; i <= aRef.Ref2.nCol; ++i) + { + aRefPos.SetCol(i); + const double* pArray = mrDoc.FetchDoubleArray(maCxt, aRefPos, nArrayLength); + if (!pArray) + return false; + + aArrays.push_back(pArray); + } + + formula::DoubleVectorRefToken aTok(aArrays, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast); + mrGroupTokens.AddToken(aTok); + } + else + { + // Absolute row reference. + ScRange aRefRange( + aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab, + aRef.Ref2.nCol, aRef.Ref2.nRow, aRef.Ref2.nTab); + + formula::FormulaTokenRef pNewToken = mrDoc.ResolveStaticReference(aRefRange); + if (!pNewToken) + return false; + + mrGroupTokens.AddToken(*pNewToken); + } + } + break; + default: + mrGroupTokens.AddToken(*pToken); + } + } + + return true; + } +}; + +} + bool ScFormulaCell::InterpretFormulaGroup() { // Re-build formulae groups if necessary - ideally this is done at @@ -2979,104 +3098,9 @@ bool ScFormulaCell::InterpretFormulaGroup() sc::FormulaGroupContext aCxt; ScTokenArray aCode; - pCode->Reset(); - for (const formula::FormulaToken* p = pCode->First(); p; p = pCode->Next()) - { - // A reference can be either absolute or relative. If it's absolute, - // convert it to a static value token. If relative, convert it to a - // vector reference token. Note: we only care about relative vs - // absolute reference state for row directions. - - const ScToken* pToken = static_cast<const ScToken*>(p); - switch (pToken->GetType()) - { - case svSingleRef: - { - ScSingleRefData aRef = pToken->GetSingleRef(); - aRef.CalcAbsIfRel(aPos); - ScAddress aRefPos(aRef.nCol, aRef.nRow, aRef.nTab); - if (aRef.IsRowRel()) - { - // Fetch double array guarantees that the length of the - // returned array equals or greater than the requested - // length. - - // TODO: For now, it returns an array pointer only when - // the entire array is in contiguous memory space. Once - // we finish cell storage rework, we'll support temporary - // generation of a double array which is a combination of - // multiple cell array segments. - const double* pArray = pDocument->FetchDoubleArray(aCxt, aRefPos, xGroup->mnLength); - if (!pArray) - return false; - - formula::SingleVectorRefToken aTok(pArray, xGroup->mnLength); - aCode.AddToken(aTok); - } - else - { - // Absolute row reference. - formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefPos); - if (!pNewToken) - return false; - - aCode.AddToken(*pNewToken); - } - } - break; - case svDoubleRef: - { - ScComplexRefData aRef = pToken->GetDoubleRef(); - aRef.CalcAbsIfRel(aPos); - if (aRef.Ref1.IsRowRel() || aRef.Ref2.IsRowRel()) - { - // Row reference is relative. - bool bAbsFirst = !aRef.Ref1.IsRowRel(); - bool bAbsLast = !aRef.Ref2.IsRowRel(); - ScAddress aRefPos(aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab); - size_t nCols = aRef.Ref2.nCol - aRef.Ref1.nCol + 1; - std::vector<const double*> aArrays; - aArrays.reserve(nCols); - SCROW nArrayLength = xGroup->mnLength; - SCROW nRefRowSize = aRef.Ref2.nRow - aRef.Ref1.nRow + 1; - if (!bAbsLast) - { - // range end position is relative. Extend the array length. - nArrayLength += nRefRowSize - 1; - } - - for (SCCOL i = aRef.Ref1.nCol; i <= aRef.Ref2.nCol; ++i) - { - aRefPos.SetCol(i); - const double* pArray = pDocument->FetchDoubleArray(aCxt, aRefPos, nArrayLength); - if (!pArray) - return false; - - aArrays.push_back(pArray); - } - - formula::DoubleVectorRefToken aTok(aArrays, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast); - aCode.AddToken(aTok); - } - else - { - // Absolute row reference. - ScRange aRefRange( - aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab, - aRef.Ref2.nCol, aRef.Ref2.nRow, aRef.Ref2.nTab); - - formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefRange); - if (!pNewToken) - return false; - - aCode.AddToken(*pNewToken); - } - } - break; - default: - aCode.AddToken(*pToken); - } - } + GroupTokenConverter aConverter(aCode, *pDocument, *this); + if (!aConverter.convert(*pCode)) + return false; sc::FormulaGroupInterpreter aInterpreter(*pDocument, aPos, xGroup, aCode); return aInterpreter.interpret(); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits