summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@gmail.com>2013-03-18 14:19:52 -0400
committerKohei Yoshida <kohei.yoshida@gmail.com>2013-03-19 13:40:22 -0400
commit6433ab29afa4d19000c14bdc0b64c0062972427e (patch)
treefb70ea164f36e9935ed05a682e4a1f6b1893a268
parent6000c8d15510b77a02d517afb81e3d2e164b318c (diff)
Implement (partially?) and test formula token array hash function.
For now, we don't factor in any differences in reference tokens in the generated hash values. Change-Id: Ie9836228eaad9c74edd884c3e8c4b273979760fd
-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);