diff options
author | Kohei Yoshida <kohei.yoshida@gmail.com> | 2013-06-03 23:47:13 -0400 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@gmail.com> | 2013-06-04 01:03:15 -0400 |
commit | 8f3e3ce107bf644772ad6d30a4d2f1d325d17f76 (patch) | |
tree | 7984a60636cedaed565ded8424861d7c92f7b837 /sc | |
parent | cd6fe27b7ff7210e4bf320f689dda41c0367d123 (diff) |
Extract the group token conversion loop out into a separate class.
Change-Id: I790db61d2a60cf4074fd2e3291ec42f0a4649b9e
Diffstat (limited to 'sc')
-rw-r--r-- | sc/source/core/data/formulacell.cxx | 220 |
1 files changed, 122 insertions, 98 deletions
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index b75bdcc08f06..11b6353db06d 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -2936,6 +2936,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 @@ -2964,104 +3083,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(); |