diff options
-rw-r--r-- | formula/source/core/api/token.cxx | 49 | ||||
-rw-r--r-- | sc/inc/column.hxx | 2 | ||||
-rw-r--r-- | sc/inc/document.hxx | 4 | ||||
-rw-r--r-- | sc/inc/table.hxx | 2 | ||||
-rw-r--r-- | sc/qa/unit/ucalc.cxx | 52 | ||||
-rw-r--r-- | sc/source/core/data/column2.cxx | 18 | ||||
-rw-r--r-- | sc/source/core/data/document.cxx | 13 | ||||
-rw-r--r-- | sc/source/core/data/table1.cxx | 8 |
8 files changed, 147 insertions, 1 deletions
diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx index f331c1e4bff5..5a47d2e43934 100644 --- a/formula/source/core/api/token.cxx +++ b/formula/source/core/api/token.cxx @@ -687,7 +687,54 @@ FormulaTokenArray* FormulaTokenArray::Clone() const size_t FormulaTokenArray::GetHash() const { - return 0; + static OUStringHash aHasher; + + size_t nHash = 1; + OpCode eOp; + StackVar eType; + const FormulaToken* p; + sal_uInt16 n = std::min<sal_uInt16>(nLen, 20); + for (sal_uInt16 i = 0; i < n; ++i) + { + p = pCode[i]; + eOp = p->GetOpCode(); + if (eOp == ocPush) + { + // This is stack variable. Do additional differentiation. + eType = p->GetType(); + switch (eType) + { + case svByte: + { + // Constant value. + sal_uInt8 nVal = p->GetByte(); + nHash += (static_cast<size_t>(nVal) << i); + continue; + } + case svDouble: + { + // Constant value. + double fVal = p->GetDouble(); + nHash += (static_cast<size_t>(fVal) << i); + continue; + } + case svString: + { + // Constant string. + const String& rStr = p->GetString(); + nHash += (aHasher(rStr) << i); + continue; + } + default: + // TODO: Decide later if we should generate hash from references as well. + ; + } + } + + // Use the opcode value in all the other cases. + nHash += (static_cast<size_t>(eOp) << i); + } + return nHash; } void FormulaTokenArray::Clear() diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 4ec4f294182d..8147c063b122 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -408,6 +408,8 @@ public: sal_uInt8 GetScriptType( SCROW nRow ) const; void SetScriptType( SCROW nRow, sal_uInt8 nType ); + size_t GetFormulaHash( SCROW nRow ) const; + private: ScBaseCell* CloneCell(SCSIZE nIndex, sal_uInt16 nFlags, ScDocument& rDestDoc, const ScAddress& rDestPos) const; diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 4dc0602da26d..7d23b89a7b27 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -750,6 +750,8 @@ public: SC_DLLPUBLIC bool SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const rtl::OUString& rString, ScSetStringParam* pParam = NULL ); + bool SetString( const ScAddress& rPos, const OUString& rString, ScSetStringParam* pParam = NULL ); + SC_DLLPUBLIC void SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal ); void SetError( SCCOL nCol, SCROW nRow, SCTAB nTab, const sal_uInt16 nError); @@ -1852,6 +1854,8 @@ public: sal_uInt8 GetScriptType( const ScAddress& rPos ) const; void SetScriptType( const ScAddress& rPos, sal_uInt8 nType ); + size_t GetFormulaHash( const ScAddress& rPos ) const; + private: // CLOOK-Impl-methods /** diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 6a0b07880fd4..2e8b697f6a8e 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -796,6 +796,8 @@ public: sal_uInt8 GetScriptType( SCCOL nCol, SCROW nRow ) const; void SetScriptType( SCCOL nCol, SCROW nRow, sal_uInt8 nType ); + size_t GetFormulaHash( SCCOL nCol, SCROW nRow ) const; + private: void FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index ec9465228ee5..4d93eb1e24be 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -116,6 +116,7 @@ public: void testCollator(); void testRangeList(); void testInput(); + void testFormulaGrouping(); void testCellFunctions(); void testCopyToDocument(); /** @@ -269,6 +270,7 @@ public: CPPUNIT_TEST(testCollator); CPPUNIT_TEST(testRangeList); CPPUNIT_TEST(testInput); + CPPUNIT_TEST(testFormulaGrouping); CPPUNIT_TEST(testCellFunctions); CPPUNIT_TEST(testCopyToDocument); CPPUNIT_TEST(testSheetsFunc); @@ -1188,6 +1190,56 @@ void testFuncINDIRECT(ScDocument* pDoc) } } +void Test::testFormulaGrouping() +{ + m_pDoc->InsertTab(0, "Test"); + + ScAddress aPos1(0,0,0), aPos2(1,0,0); + + // simplest cases. + m_pDoc->SetString(aPos1, "=1"); + size_t nHashVal1 = m_pDoc->GetFormulaHash(aPos1); + m_pDoc->SetString(aPos2, "=2"); + size_t nHashVal2 = m_pDoc->GetFormulaHash(aPos2); + CPPUNIT_ASSERT_MESSAGE("These hashes should differ.", nHashVal1 != nHashVal2); + + // different cell functions. + aPos1.IncRow(); + aPos2.IncRow(); + m_pDoc->SetString(aPos1, "=SUM(1,2,3,4,5)"); + m_pDoc->SetString(aPos2, "=AVERAGE(1,2,3,4,5)"); + nHashVal1 = m_pDoc->GetFormulaHash(aPos1); + nHashVal2 = m_pDoc->GetFormulaHash(aPos2); + CPPUNIT_ASSERT_MESSAGE("These hashes should differ.", nHashVal1 != nHashVal2); + + // same relative references. + aPos1.IncRow(); + aPos2.IncRow(); + m_pDoc->SetString(aPos1, "=A2*3"); + m_pDoc->SetString(aPos2, "=B2*3"); + nHashVal1 = m_pDoc->GetFormulaHash(aPos1); + nHashVal2 = m_pDoc->GetFormulaHash(aPos2); + CPPUNIT_ASSERT_MESSAGE("These hashes should be equal.", nHashVal1 == nHashVal2); + + m_pDoc->SetString(aPos2, "=B2*4"); // Change the constant. + nHashVal2 = m_pDoc->GetFormulaHash(aPos2); + CPPUNIT_ASSERT_MESSAGE("These hashes should differ.", nHashVal1 != nHashVal2); + + m_pDoc->SetString(aPos1, "=A2*4"); // Change the constant again to make it "equal". + nHashVal1 = m_pDoc->GetFormulaHash(aPos1); + CPPUNIT_ASSERT_MESSAGE("These hashes should be equal.", nHashVal1 == nHashVal2); + + aPos1.IncRow(); + aPos2.IncRow(); + m_pDoc->SetString(aPos1, "=3*4*5"); + m_pDoc->SetString(aPos2, "=3*4*\"foo\""); + nHashVal1 = m_pDoc->GetFormulaHash(aPos1); + nHashVal2 = m_pDoc->GetFormulaHash(aPos2); + CPPUNIT_ASSERT_MESSAGE("These hashes should differ.", nHashVal1 != nHashVal2); + + m_pDoc->DeleteTab(0); +} + void Test::testCellFunctions() { OUString aTabName("foo"); diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index 330154226f14..ea4be5ba4c90 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -1525,6 +1525,24 @@ void ScColumn::SetScriptType( SCROW nRow, sal_uInt8 nType ) maScriptTypes.set<unsigned short>(nRow, nType); } +size_t ScColumn::GetFormulaHash( SCROW nRow ) const +{ + if (!ValidRow(nRow)) + return 0; + + SCSIZE nIndex; + if (!Search(nRow, nIndex)) + // cell not found. + return 0; + + const ScBaseCell* pCell = maItems[nIndex].pCell; + if (pCell->GetCellType() != CELLTYPE_FORMULA) + // Not a formula cell. + return 0; + + return static_cast<const ScFormulaCell*>(pCell)->GetHash(); +} + void ScColumn::FindDataAreaPos(SCROW& rRow, bool bDown) const { // check if we are in a data area diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 3a1247ad2cb8..1f237d13b0c7 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -1552,6 +1552,14 @@ bool ScDocument::HasPartOfMerged( const ScRange& rRange ) return bPart; } +size_t ScDocument::GetFormulaHash( const ScAddress& rPos ) const +{ + SCTAB nTab = rPos.Tab(); + if (!ValidTab(nTab) || static_cast<size_t>(nTab) >= maTabs.size() || !maTabs[nTab]) + return 0; + + return maTabs[nTab]->GetFormulaHash(rPos.Col(), rPos.Row()); +} bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew ) { @@ -2939,6 +2947,11 @@ bool ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString& return false; } +bool ScDocument::SetString( + const ScAddress& rPos, const OUString& rString, ScSetStringParam* pParam ) +{ + return SetString(rPos.Col(), rPos.Row(), rPos.Tab(), rString, pParam); +} void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal ) { diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index fd5026f22593..ee90ae4c4c63 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -2096,6 +2096,14 @@ void ScTable::SetScriptType( SCCOL nCol, SCROW nRow, sal_uInt8 nType ) aCol[nCol].SetScriptType(nRow, nType); } +size_t ScTable::GetFormulaHash( SCCOL nCol, SCROW nRow ) const +{ + if (!ValidCol(nCol)) + return 0; + + return aCol[nCol].GetFormulaHash(nRow); +} + void ScTable::DeleteConditionalFormat( sal_uLong nIndex ) { mpCondFormatList->erase(nIndex); |