summaryrefslogtreecommitdiff
path: root/sc/source
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@gmail.com>2013-04-26 22:53:04 -0400
committerKohei Yoshida <kohei.yoshida@gmail.com>2013-04-30 13:10:40 -0400
commit34c491dabedf3ce4feb1db6d00df33e5573ec03c (patch)
tree4d4e93e817c27aa10fb52a0d7edbdd1c5717bd16 /sc/source
parentf32534cedd414e57790782794cacdd0f0f4adb7c (diff)
Handle invariant group with single references.
Change-Id: Ifbbac2b11b1023a5cf3d21204c12b9740af09aaf
Diffstat (limited to 'sc/source')
-rw-r--r--sc/source/core/data/column2.cxx70
-rw-r--r--sc/source/core/data/document.cxx16
-rw-r--r--sc/source/core/data/formulacell.cxx126
-rw-r--r--sc/source/core/data/table1.cxx28
4 files changed, 181 insertions, 59 deletions
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index e95dcf93a6c4..20483f84a4d2 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1589,28 +1589,78 @@ ScFormulaVectorState ScColumn::GetFormulaVectorState( SCROW nRow ) const
return pCell ? pCell->GetVectorState() : FormulaVectorUnknown;
}
-bool ScColumn::ResolveVectorReference( SCROW nRow1, SCROW nRow2 )
+formula::FormulaTokenRef ScColumn::ResolveStaticReference( SCROW nRow )
{
std::vector<ColEntry>::iterator itEnd = maItems.end();
// Find first cell whose position is equal or greater than nRow1.
ColEntry aBound;
- aBound.nRow = nRow1;
+ aBound.nRow = nRow;
std::vector<ColEntry>::iterator it =
std::lower_bound(maItems.begin(), itEnd, aBound, ColEntry::Less());
- if (it == itEnd)
+ if (it == itEnd || it->nRow != nRow)
+ {
+ // Empty cell.
+ return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
+ }
+
+ ScBaseCell* pCell = it->pCell;
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ {
+ ScValueCell* pVC = static_cast<ScValueCell*>(pCell);
+ return formula::FormulaTokenRef(new formula::FormulaDoubleToken(pVC->GetValue()));
+ }
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFC = static_cast<ScFormulaCell*>(pCell);
+ if (pFC->GetDirty())
+ // Dirty formula cell is not considered static. Return null token.
+ return formula::FormulaTokenRef();
+
+ return formula::FormulaTokenRef(new formula::FormulaDoubleToken(pFC->GetResultDouble()));
+ }
+ default:
+ ;
+ }
+
+ return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
+}
+
+bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 )
+{
+ if (nRow1 > nRow2)
return false;
+ std::vector<ColEntry>::iterator itEnd = maItems.end();
+ // Find first cell whose position is equal or greater than nRow1.
+ ColEntry aBound;
+ aBound.nRow = nRow1;
+ std::vector<ColEntry>::iterator it =
+ std::lower_bound(maItems.begin(), itEnd, aBound, ColEntry::Less());
+
for (; it != itEnd && it->nRow <= nRow2; ++it)
{
- if (it->pCell->GetCellType() != CELLTYPE_FORMULA)
- // Non-formula cells are fine.
- continue;
+ switch (it->pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ {
+ ScValueCell* pVC = static_cast<ScValueCell*>(it->pCell);
+ rMat.PutDouble(pVC->GetValue(), nMatCol, it->nRow - nRow1);
+ }
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFC = static_cast<ScFormulaCell*>(it->pCell);
+ if (pFC->GetDirty())
+ // Dirty formula cell is not considered static. Return null token.
+ return false;
- ScFormulaCell* pFC = static_cast<ScFormulaCell*>(it->pCell);
- if (pFC->GetDirty())
- // Dirty formula cells are not supported yet.
- return false;
+ rMat.PutDouble(pFC->GetResultDouble(), nMatCol, it->nRow - nRow1);
+ }
+ default:
+ ;
+ }
}
return true;
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 6a00d36d0b6e..9a3dcf7b1668 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1574,13 +1574,23 @@ ScFormulaVectorState ScDocument::GetFormulaVectorState( const ScAddress& rPos )
return maTabs[nTab]->GetFormulaVectorState(rPos.Col(), rPos.Row());
}
-bool ScDocument::ResolveVectorReference( const ScAddress& rPos, SCROW nEndRow )
+formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScAddress& rPos )
{
SCTAB nTab = rPos.Tab();
if (!TableExists(nTab))
- return false;
+ return formula::FormulaTokenRef();
+
+ return maTabs[nTab]->ResolveStaticReference(rPos.Col(), rPos.Row());
+}
+
+formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRange )
+{
+ SCTAB nTab = rRange.aStart.Tab();
+ if (nTab != rRange.aEnd.Tab() || !TableExists(nTab))
+ return formula::FormulaTokenRef();
- return maTabs[nTab]->ResolveVectorReference(rPos.Col(), rPos.Row(), nEndRow);
+ return maTabs[nTab]->ResolveStaticReference(
+ rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
}
bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index e73641d606b0..43d80cf906df 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2954,27 +2954,75 @@ bool ScFormulaCell::InterpretFormulaGroup()
switch (pCode->GetVectorState())
{
case FormulaVectorEnabled:
+ case FormulaVectorCheckReference:
// Good.
break;
- case FormulaVectorCheckReference:
- // To support this we would need a real range-based dependency
- // tracking. We can't support this right now.
- return false;
case FormulaVectorDisabled:
case FormulaVectorUnknown:
default:
+ // Not good.
return false;
}
-// fprintf( stderr, "Interpret cell %d, %d\n", (int)aPos.Col(), (int)aPos.Row() );
-
if (xGroup->mbInvariant)
{
-// fprintf( stderr, "struck gold - completely invariant for %d items !\n",
-// (int)xGroup->mnLength );
+ if (pCode->GetVectorState() == FormulaVectorCheckReference)
+ {
+ // An invariant group should only have absolute references, and no
+ // external references are allowed.
+
+ ScTokenArray aCode;
+ pCode->Reset();
+ for (const formula::FormulaToken* p = pCode->First(); p; p = pCode->Next())
+ {
+ const ScToken* pToken = static_cast<const ScToken*>(p);
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ {
+ const ScSingleRefData& rRef = pToken->GetSingleRef();
+ ScAddress aRefPos(rRef.nCol, rRef.nRow, rRef.nTab);
+ formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefPos);
+ if (!pNewToken)
+ return false;
+
+ aCode.AddToken(*pNewToken);
+ }
+ break;
+ case svDoubleRef:
+ {
+ const ScComplexRefData& rRef = pToken->GetDoubleRef();
+ ScRange aRefRange(
+ rRef.Ref1.nCol, rRef.Ref1.nRow, rRef.Ref1.nTab,
+ rRef.Ref2.nCol, rRef.Ref2.nRow, rRef.Ref2.nTab);
+
+ formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefRange);
+ if (!pNewToken)
+ return false;
+
+ aCode.AddToken(*pNewToken);
+ }
+ break;
+ default:
+ aCode.AddToken(*pToken);
+ }
+ }
+
+ ScCompiler aComp(pDocument, aPos, aCode);
+ aComp.SetGrammar(pDocument->GetGrammar());
+ aComp.CompileTokenArray(); // Create RPN token array.
+ ScInterpreter aInterpreter(this, pDocument, aPos, aCode);
+ aInterpreter.Interpret();
+ aResult.SetToken(aInterpreter.GetResultToken().get());
+ }
+ else
+ {
+ // Formula contains no references.
+ ScInterpreter aInterpreter(this, pDocument, aPos, *pCode);
+ aInterpreter.Interpret();
+ aResult.SetToken(aInterpreter.GetResultToken().get());
+ }
- // calculate ourselves:
- InterpretTail( SCITP_NORMAL );
for ( sal_Int32 i = 0; i < xGroup->mnLength; i++ )
{
ScAddress aTmpPos = aPos;
@@ -2993,37 +3041,35 @@ bool ScFormulaCell::InterpretFormulaGroup()
}
return true;
}
- else
- {
- // scan the formula ...
- // have a document method: "Get2DRangeAsDoublesArray" that does the
- // column-based heavy lifting call it for each absolute range from the
- // first cell pos in the formula group.
- //
- // Project single references to ranges by adding their vector * xGroup->mnLength
- //
- // TODO:
- // elide multiple dimensional movement in vectors eg. =SUM(A1<1,1>)
- // produces a diagonal 'column' that serves no useful purpose for us.
- // these should be very rare. Should elide in GetDeltas anyway and
- // assert here.
- //
- // Having built our input data ...
- // Throw it, and the formula over to some 'OpenCLCalculage' hook
- //
- // on return - release references on these double buffers
- //
- // transfer the result to the formula cells (as above)
- // store the doubles in the columns' maDoubles array for
- // dependent formulae
- //
- // TODO:
- // need to abort/fail when we get errors returned and fallback to
- // stock interpreting [ I guess ], unless we can use NaN etc. to
- // signal errors.
- return false;
- }
+ // scan the formula ...
+ // have a document method: "Get2DRangeAsDoublesArray" that does the
+ // column-based heavy lifting call it for each absolute range from the
+ // first cell pos in the formula group.
+ //
+ // Project single references to ranges by adding their vector * xGroup->mnLength
+ //
+ // TODO:
+ // elide multiple dimensional movement in vectors eg. =SUM(A1<1,1>)
+ // produces a diagonal 'column' that serves no useful purpose for us.
+ // these should be very rare. Should elide in GetDeltas anyway and
+ // assert here.
+ //
+ // Having built our input data ...
+ // Throw it, and the formula over to some 'OpenCLCalculage' hook
+ //
+ // on return - release references on these double buffers
+ //
+ // transfer the result to the formula cells (as above)
+ // store the doubles in the columns' maDoubles array for
+ // dependent formulae
+ //
+ // TODO:
+ // need to abort/fail when we get errors returned and fallback to
+ // stock interpreting [ I guess ], unless we can use NaN etc. to
+ // signal errors.
+
+ return false;
}
void ScFormulaCell::StartListeningTo( ScDocument* pDoc )
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 7ae3c66ea8d7..52e0bb98c8e2 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2113,15 +2113,31 @@ ScFormulaVectorState ScTable::GetFormulaVectorState( SCCOL nCol, SCROW nRow ) co
return aCol[nCol].GetFormulaVectorState(nRow);
}
-bool ScTable::ResolveVectorReference( SCCOL nCol, SCROW nRow1, SCROW nRow2 )
+formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol, SCROW nRow )
{
- if (!ValidCol(nCol) || !ValidRow(nRow1) || !ValidRow(nRow2))
- return false;
+ if (!ValidCol(nCol) || !ValidRow(nRow))
+ return formula::FormulaTokenRef();
- if (!aCol[nCol].ResolveVectorReference(nRow1, nRow2))
- return false;
+ return aCol[nCol].ResolveStaticReference(nRow);
+}
- return true;
+formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+ if (nCol2 < nCol1 || nRow2 < nRow1)
+ return formula::FormulaTokenRef();
+
+ if (!ValidCol(nCol1) || !ValidCol(nCol2) || !ValidRow(nRow1) || !ValidRow(nRow2))
+ return formula::FormulaTokenRef();
+
+ ScMatrixRef pMat(new ScMatrix(nCol2-nCol1+1, nRow2-nRow1+1, 0.0));
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ {
+ if (!aCol[nCol].ResolveStaticReference(*pMat, nCol2-nCol1, nRow1, nRow2))
+ // Column contains non-static cell. Failed.
+ return formula::FormulaTokenRef();
+ }
+
+ return formula::FormulaTokenRef(new ScMatrixToken(pMat));
}
ScRefCellValue ScTable::GetRefCellValue( SCCOL nCol, SCROW nRow )