diff options
-rw-r--r-- | formula/source/core/api/vectortoken.cxx | 4 | ||||
-rw-r--r-- | include/formula/vectortoken.hxx | 4 | ||||
-rw-r--r-- | sc/inc/column.hxx | 9 | ||||
-rw-r--r-- | sc/inc/document.hxx | 2 | ||||
-rw-r--r-- | sc/inc/table.hxx | 1 | ||||
-rw-r--r-- | sc/source/core/data/column.cxx | 21 | ||||
-rw-r--r-- | sc/source/core/data/column2.cxx | 56 | ||||
-rw-r--r-- | sc/source/core/data/document.cxx | 9 | ||||
-rw-r--r-- | sc/source/core/data/formulacell.cxx | 90 | ||||
-rw-r--r-- | sc/source/core/data/table1.cxx | 11 |
10 files changed, 183 insertions, 24 deletions
diff --git a/formula/source/core/api/vectortoken.cxx b/formula/source/core/api/vectortoken.cxx index b7cab77e0136..0c2e45577198 100644 --- a/formula/source/core/api/vectortoken.cxx +++ b/formula/source/core/api/vectortoken.cxx @@ -23,9 +23,9 @@ const VectorArray& SingleVectorRefToken::GetArray() const } DoubleVectorRefToken::DoubleVectorRefToken( - const std::vector<VectorArray>& rArrays, size_t nColSize, size_t nRowSize, bool bAbsStart, bool bAbsEnd ) : + const std::vector<VectorArray>& rArrays, size_t nRowSize, bool bAbsStart, bool bAbsEnd ) : FormulaToken(svDoubleVectorRef, ocPush), - maArrays(rArrays), mnColSize(nColSize), mnRowSize(nRowSize), mbAbsStart(bAbsStart), mbAbsEnd(bAbsEnd) {} + maArrays(rArrays), mnRowSize(nRowSize), mbAbsStart(bAbsStart), mbAbsEnd(bAbsEnd) {} const std::vector<VectorArray>& DoubleVectorRefToken::GetArrays() const { diff --git a/include/formula/vectortoken.hxx b/include/formula/vectortoken.hxx index 5af2690a5de6..90e28d836a75 100644 --- a/include/formula/vectortoken.hxx +++ b/include/formula/vectortoken.hxx @@ -39,7 +39,6 @@ class FORMULA_DLLPUBLIC DoubleVectorRefToken : public FormulaToken { std::vector<VectorArray> maArrays; - size_t mnColSize; size_t mnRowSize; bool mbAbsStart:1; /// whether or not the start row position is absolute. @@ -47,8 +46,7 @@ class FORMULA_DLLPUBLIC DoubleVectorRefToken : public FormulaToken public: DoubleVectorRefToken( - const std::vector<VectorArray>& rArrays, size_t nColSize, size_t nRowSize, - bool bAbsStart, bool bAbsEnd ); + const std::vector<VectorArray>& rArrays, size_t nRowSize, bool bAbsStart, bool bAbsEnd ); const std::vector<VectorArray>& GetArrays() const; }; diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 157bc173e98f..6b3202ae6f1c 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -106,6 +106,11 @@ struct ColDoubleEntry { SCROW mnStart; std::vector<double> maData; + + struct LessByPtr : std::binary_function<ColDoubleEntry*, ColDoubleEntry*, bool> + { + bool operator() (const ColDoubleEntry* p1, const ColDoubleEntry* p2) const; + }; }; class ScColumn @@ -155,6 +160,9 @@ friend class ScDocumentImport; static void SwapScriptTypes( ScriptType& rSrc, SCROW nSrcRow, ScriptType& rDest, SCROW nDestRow ); + std::vector<ColEntry>::iterator Search( SCROW nRow ); + std::vector<ColEntry>::const_iterator Search( SCROW nRow ) const; + public: ScColumn(); ~ScColumn(); @@ -452,6 +460,7 @@ public: ScFormulaVectorState GetFormulaVectorState( SCROW nRow ) const; formula::FormulaTokenRef ResolveStaticReference( SCROW nRow ); bool ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 ); + const double* FetchDoubleArray( SCROW nRow1, SCROW nRow2 ) const; ScRefCellValue GetRefCellValue( SCROW ); diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index cdb80e041e95..876c9d764eb0 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -1944,6 +1944,8 @@ public: formula::FormulaTokenRef ResolveStaticReference( const ScAddress& rPos ); formula::FormulaTokenRef ResolveStaticReference( const ScRange& rRange ); + const double* FetchDoubleArray( const ScAddress& rPos, SCROW nLength ) const; + private: // CLOOK-Impl-methods /** diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index c04b902135d1..7c45a578274c 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -822,6 +822,7 @@ public: ScFormulaVectorState GetFormulaVectorState( SCCOL nCol, SCROW nRow ) const; formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol, SCROW nRow ); formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ); + const double* FetchDoubleArray( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const; ScRefCellValue GetRefCellValue( SCCOL nCol, SCROW nRow ); diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 0c3e630e3a0c..17bbe687ceb8 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -50,6 +50,11 @@ bool ColEntry::Less::operator() (const ColEntry& r1, const ColEntry& r2) const return r1.nRow < r2.nRow; } +bool ColDoubleEntry::LessByPtr::operator() (const ColDoubleEntry* p1, const ColDoubleEntry* p2) const +{ + return p1->mnStart < p2->mnStart; +} + namespace { inline bool IsAmbiguousScriptNonZero( sal_uInt8 nScript ) @@ -89,6 +94,22 @@ void ScColumn::SwapScriptTypes( ScriptType& rSrc, SCROW nSrcRow, ScriptType& rDe rDest.set_empty(nDestRow, nDestRow); } +std::vector<ColEntry>::iterator ScColumn::Search( SCROW nRow ) +{ + // Find first cell whose position is equal or greater than nRow. + ColEntry aBound; + aBound.nRow = nRow; + return std::lower_bound(maItems.begin(), maItems.end(), aBound, ColEntry::Less()); +} + +std::vector<ColEntry>::const_iterator ScColumn::Search( SCROW nRow ) const +{ + // Find first cell whose position is equal or greater than nRow. + ColEntry aBound; + aBound.nRow = nRow; + return std::lower_bound(maItems.begin(), maItems.end(), aBound, ColEntry::Less()); +} + ScColumn::ScColumn() : maTextWidths(MAXROWCOUNT), maScriptTypes(MAXROWCOUNT), diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index 6bcf2829af2c..25725ae5fa57 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -1591,12 +1591,8 @@ ScFormulaVectorState ScColumn::GetFormulaVectorState( SCROW nRow ) const formula::FormulaTokenRef ScColumn::ResolveStaticReference( SCROW nRow ) { + std::vector<ColEntry>::iterator it = Search(nRow); std::vector<ColEntry>::iterator itEnd = maItems.end(); - // Find first cell whose position is equal or greater than nRow1. - ColEntry aBound; - aBound.nRow = nRow; - std::vector<ColEntry>::iterator it = - std::lower_bound(maItems.begin(), itEnd, aBound, ColEntry::Less()); if (it == itEnd || it->nRow != nRow) { @@ -1633,12 +1629,8 @@ bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow if (nRow1 > nRow2) return false; + std::vector<ColEntry>::iterator it = Search(nRow1); 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) { @@ -1668,6 +1660,50 @@ bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow return true; } +const double* ScColumn::FetchDoubleArray( SCROW nRow1, SCROW nRow2 ) const +{ + 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) + { + SCROW nLastRow = rEntry.mnStart + rEntry.maData.size() - 1; + if (nLastRow < nRow2) + // Array is shorter than requested length. + return NULL; + + return &rEntry.maData[0]; + } + + 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. + return NULL; + + return &rEntry.maData[nRow1 - rEntry.mnStart]; +} + ScRefCellValue ScColumn::GetRefCellValue( SCROW nRow ) { ScRefCellValue aCell; // start empty diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 9a3dcf7b1668..c4f93c6e0e97 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -1593,6 +1593,15 @@ formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRan rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row()); } +const double* ScDocument::FetchDoubleArray( const ScAddress& rPos, SCROW nLength ) const +{ + SCTAB nTab = rPos.Tab(); + if (!TableExists(nTab)) + return NULL; + + return maTabs[nTab]->FetchDoubleArray(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1); +} + bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew ) { if ( rOld == rNew ) diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 3bfd458320fd..20ec752e4053 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -40,6 +40,7 @@ #include "tokenarray.hxx" #include "formula/errorcodes.hxx" +#include "formula/vectortoken.hxx" #include "svl/intitem.hxx" #include "rtl/strbuf.hxx" @@ -2912,7 +2913,7 @@ ScFormulaCell::CompareState ScFormulaCell::CompareByTokenArray( ScFormulaCell *p if (rRef != pOtherTok->GetSingleRef()) return NotEqual; - if (rRef.IsColRel() || rRef.IsRowRel()) + if (rRef.IsRowRel()) bInvariant = false; } break; @@ -2927,10 +2928,10 @@ ScFormulaCell::CompareState ScFormulaCell::CompareByTokenArray( ScFormulaCell *p if (rRef2 != pOtherTok->GetSingleRef2()) return NotEqual; - if (rRef1.IsColRel() || rRef1.IsRowRel()) + if (rRef1.IsRowRel()) bInvariant = false; - if (rRef2.IsColRel() || rRef2.IsRowRel()) + if (rRef2.IsRowRel()) bInvariant = false; } break; @@ -2967,6 +2968,75 @@ bool ScFormulaCell::InterpretFormulaGroup() if (xGroup->mbInvariant) return InterpretInvariantFormulaGroup(); + 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. + const double* pArray = pDocument->FetchDoubleArray(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()) + { + // TODO: Implement this. + return false; + } + 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); + } + } + // scan the formula ... // have a document method: "Get2DRangeAsDoublesArray" that does the // column-based heavy lifting call it for each absolute range from the @@ -3001,7 +3071,7 @@ bool ScFormulaCell::InterpretInvariantFormulaGroup() { if (pCode->GetVectorState() == FormulaVectorCheckReference) { - // An invariant group should only have absolute references, and no + // An invariant group should only have absolute row references, and no // external references are allowed. ScTokenArray aCode; @@ -3013,8 +3083,9 @@ bool ScFormulaCell::InterpretInvariantFormulaGroup() { case svSingleRef: { - const ScSingleRefData& rRef = pToken->GetSingleRef(); - ScAddress aRefPos(rRef.nCol, rRef.nRow, rRef.nTab); + ScSingleRefData aRef = pToken->GetSingleRef(); + aRef.CalcAbsIfRel(aPos); // column may be relative. + ScAddress aRefPos(aRef.nCol, aRef.nRow, aRef.nTab); formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefPos); if (!pNewToken) return false; @@ -3024,10 +3095,11 @@ bool ScFormulaCell::InterpretInvariantFormulaGroup() break; case svDoubleRef: { - const ScComplexRefData& rRef = pToken->GetDoubleRef(); + ScComplexRefData aRef = pToken->GetDoubleRef(); + aRef.CalcAbsIfRel(aPos); // column may be relative. ScRange aRefRange( - rRef.Ref1.nCol, rRef.Ref1.nRow, rRef.Ref1.nTab, - rRef.Ref2.nCol, rRef.Ref2.nRow, rRef.Ref2.nTab); + 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) diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index 52e0bb98c8e2..a6c60425328f 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -2140,6 +2140,17 @@ formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol1, SCROW nRo return formula::FormulaTokenRef(new ScMatrixToken(pMat)); } +const double* ScTable::FetchDoubleArray( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const +{ + if (nRow2 < nRow1) + return NULL; + + if (!ValidCol(nCol) || !ValidRow(nRow1) || !ValidRow(nRow2)) + return NULL; + + return aCol[nCol].FetchDoubleArray(nRow1, nRow1); +} + ScRefCellValue ScTable::GetRefCellValue( SCCOL nCol, SCROW nRow ) { if (!ValidColRow(nCol, nRow)) |