diff options
author | Kohei Yoshida <kohei.yoshida@gmail.com> | 2013-04-26 22:53:04 -0400 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@gmail.com> | 2013-04-30 13:10:40 -0400 |
commit | 34c491dabedf3ce4feb1db6d00df33e5573ec03c (patch) | |
tree | 4d4e93e817c27aa10fb52a0d7edbdd1c5717bd16 /sc | |
parent | f32534cedd414e57790782794cacdd0f0f4adb7c (diff) |
Handle invariant group with single references.
Change-Id: Ifbbac2b11b1023a5cf3d21204c12b9740af09aaf
Diffstat (limited to 'sc')
-rw-r--r-- | sc/inc/column.hxx | 7 | ||||
-rw-r--r-- | sc/inc/document.hxx | 11 | ||||
-rw-r--r-- | sc/inc/formulacell.hxx | 2 | ||||
-rw-r--r-- | sc/inc/table.hxx | 4 | ||||
-rw-r--r-- | sc/inc/token.hxx | 4 | ||||
-rw-r--r-- | sc/inc/types.hxx | 3 | ||||
-rw-r--r-- | sc/source/core/data/column2.cxx | 70 | ||||
-rw-r--r-- | sc/source/core/data/document.cxx | 16 | ||||
-rw-r--r-- | sc/source/core/data/formulacell.cxx | 126 | ||||
-rw-r--r-- | sc/source/core/data/table1.cxx | 28 |
10 files changed, 198 insertions, 73 deletions
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 866fce3bf113..157bc173e98f 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -25,11 +25,13 @@ #include "address.hxx" #include "rangenam.hxx" #include "types.hxx" -#include <boost/intrusive_ptr.hpp> +#include "formula/types.hxx" #include <set> #include <vector> +#include <boost/intrusive_ptr.hpp> + #define DEBUG_COLUMN_STORAGE 0 #if DEBUG_COLUMN_STORAGE @@ -448,7 +450,8 @@ public: size_t GetFormulaHash( SCROW nRow ) const; ScFormulaVectorState GetFormulaVectorState( SCROW nRow ) const; - bool ResolveVectorReference( SCROW nRow1, SCROW nRow2 ); + formula::FormulaTokenRef ResolveStaticReference( SCROW nRow ); + bool ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 ); ScRefCellValue GetRefCellValue( SCROW ); diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 052b81d208e9..cdb80e041e95 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -32,6 +32,7 @@ #include "sortparam.hxx" #include "types.hxx" #include "formula/grammar.hxx" +#include "formula/types.hxx" #include <com/sun/star/chart2/XChartDocument.hpp> #include "typedstrdata.hxx" #include "compressedarray.hxx" @@ -1940,14 +1941,8 @@ public: ScFormulaVectorState GetFormulaVectorState( const ScAddress& rPos ) const; - /** - * Check if the range contains any "dirty" formula cells. In the future - * we'll use this function to interpret those "dirty" formula cells on - * demand. - * - * @return true if the range is totally clean, false otherwise. - */ - bool ResolveVectorReference( const ScAddress& rPos, SCROW nEndRow ); + formula::FormulaTokenRef ResolveStaticReference( const ScAddress& rPos ); + formula::FormulaTokenRef ResolveStaticReference( const ScRange& rRange ); private: // CLOOK-Impl-methods diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index e6239e3f2226..397fd9c72fe4 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -282,6 +282,8 @@ public: */ void SetResultDouble( double n ) { aResult.SetDouble( n); } + double GetResultDouble() const { return aResult.GetDouble(); } + void SetErrCode( sal_uInt16 n ); bool IsHyperLinkCell() const; EditTextObject* CreateURLObject(); diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index eb5f7561a1ef..c04b902135d1 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -30,6 +30,7 @@ #include "compressedarray.hxx" #include "postit.hxx" #include "types.hxx" +#include "formula/types.hxx" #include <set> #include <map> @@ -819,7 +820,8 @@ public: size_t GetFormulaHash( SCCOL nCol, SCROW nRow ) const; ScFormulaVectorState GetFormulaVectorState( SCCOL nCol, SCROW nRow ) const; - bool ResolveVectorReference( SCCOL nCol, SCROW nRow1, SCROW nRow2 ); + formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol, SCROW nRow ); + formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ); ScRefCellValue GetRefCellValue( SCCOL nCol, SCROW nRow ); diff --git a/sc/inc/token.hxx b/sc/inc/token.hxx index a54055561bae..abd3cd5c06cc 100644 --- a/sc/inc/token.hxx +++ b/sc/inc/token.hxx @@ -31,13 +31,11 @@ #include "scdllapi.h" #include "formula/IFunctionDescription.hxx" #include "formula/token.hxx" - +#include "types.hxx" class ScJumpMatrix; -class ScToken; typedef ::std::vector< ScComplexRefData > ScRefList; -typedef ::boost::intrusive_ptr<ScToken> ScTokenRef; class SC_DLLPUBLIC ScToken : public formula::FormulaToken { diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx index 7227472aa949..1af6e2d73b62 100644 --- a/sc/inc/types.hxx +++ b/sc/inc/types.hxx @@ -17,6 +17,9 @@ class ScMatrix; typedef ::boost::intrusive_ptr<ScMatrix> ScMatrixRef; typedef ::boost::intrusive_ptr<const ScMatrix> ScConstMatrixRef; +class ScToken; +typedef ::boost::intrusive_ptr<ScToken> ScTokenRef; + /** * When vectorization is enabled, we could potentially mass-calculate a * series of formula token arrays in adjacent formula cells in one step, 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 ) |