summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--formula/source/core/api/token.cxx49
-rw-r--r--sc/inc/column.hxx2
-rw-r--r--sc/inc/document.hxx4
-rw-r--r--sc/inc/table.hxx2
-rw-r--r--sc/qa/unit/ucalc.cxx52
-rw-r--r--sc/source/core/data/column2.cxx18
-rw-r--r--sc/source/core/data/document.cxx13
-rw-r--r--sc/source/core/data/table1.cxx8
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);