[Libreoffice-commits] core.git: Branch 'feature/calc-group-interpreter' - 2 commits - sc/source
Kohei Yoshida
kohei.yoshida at gmail.com
Mon Jun 3 21:59:37 PDT 2013
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.yoshida at 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.yoshida at 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();
More information about the Libreoffice-commits
mailing list