[Libreoffice-commits] core.git: Branch 'feature/formula-core-rework' - sc/qa sc/source
Kohei Yoshida
kohei.yoshida at gmail.com
Mon Mar 18 13:26:43 PDT 2013
sc/qa/unit/ucalc.cxx | 82 +++++++++++++++++++++---------------------
sc/source/core/tool/token.cxx | 40 ++++++++++++++++++--
2 files changed, 78 insertions(+), 44 deletions(-)
New commits:
commit f974be31a7881c4ad72d9c29b4db3c435bd99ba5
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date: Mon Mar 18 16:28:11 2013 -0400
Embed reference tokens in the generated hash values.
Also make the test code a bit easier to extend.
Change-Id: Ib4e381cc139231884999c9d0dc9f51201e11f807
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index b6addd1..3e9a14d 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -1196,47 +1196,47 @@ void Test::testFormulaGrouping()
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);
-
- // string constant vs numeric constant.
- 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);
+ struct {
+ const char* pFormula1; const char* pFormula2; bool bEqual;
+ } aTests[] = {
+ { "=1", "=2", false }, // different constants
+ { "=SUM(1;2;3;4;5)", "=AVERAGE(1;2;3;4;5)", false }, // different functions
+ { "=C2*3", "=D2*3", true }, // relative references
+ { "=C2*3", "=D2*4", false }, // different constants
+ { "=C2*4", "=D2*4", true }, // relative references
+ { "=3*4*5", "=3*4*\"foo\"", false }, // numeric vs string constants
+ { "=$C3/2", "=$C3/2", true }, // absolute column references
+ { "=C$3/2", "=D$3/2", true }, // absolute row references
+ { "=$E$30/2", "=$E$30/2", true }, // absolute references
+ { "=X20", "=$X$20", false }, // absolute vs relative
+ { "=X20", "=X$20", false }, // absolute vs relative
+ { "=X20", "=$X20", false }, // absolute vs relative
+ { "=X$20", "=$X20", false }, // column absolute vs row absolute
+ };
+
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i)
+ {
+ m_pDoc->SetString(aPos1, OUString::createFromAscii(aTests[i].pFormula1));
+ m_pDoc->SetString(aPos2, OUString::createFromAscii(aTests[i].pFormula2));
+ size_t nHashVal1 = m_pDoc->GetFormulaHash(aPos1);
+ size_t nHashVal2 = m_pDoc->GetFormulaHash(aPos2);
+
+ std::ostringstream os;
+ os << "(expr1:" << aTests[i].pFormula1 << "; expr2:" << aTests[i].pFormula2 << ")";
+ if (aTests[i].bEqual)
+ {
+ os << " Error: these hashes should be equal." << endl;
+ CPPUNIT_ASSERT_MESSAGE(os.str().c_str(), nHashVal1 == nHashVal2);
+ }
+ else
+ {
+ os << " Error: these hashes should differ." << endl;
+ CPPUNIT_ASSERT_MESSAGE(os.str().c_str(), nHashVal1 != nHashVal2);
+ }
+
+ aPos1.IncRow();
+ aPos2.IncRow();
+ }
m_pDoc->DeleteTab(0);
}
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index b400f6d..a19f2e3 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -1274,6 +1274,26 @@ bool ScTokenArray::ImplGetReference( ScRange& rRange, bool bValidOnly ) const
return bIs;
}
+namespace {
+
+size_t HashSingleRef( const ScSingleRefData& rRef )
+{
+ SCsCOL nCol = rRef.Flags.bColRel ? rRef.nRelCol : rRef.nCol;
+ SCsROW nRow = rRef.Flags.bRowRel ? rRef.nRelRow : rRef.nRow;
+ SCsTAB nTab = rRef.Flags.bTabRel ? rRef.nRelTab : rRef.nTab;
+ size_t nVal = nCol;
+ nVal += (nRow << 8);
+ nVal += (nTab << 16);
+
+ // Embed flag values too.
+ nVal += rRef.Flags.bColRel;
+ nVal += (rRef.Flags.bRowRel << 1);
+ nVal += (rRef.Flags.bTabRel << 2);
+ return nVal;
+}
+
+}
+
size_t ScTokenArray::GetHash() const
{
static OUStringHash aHasher;
@@ -1281,11 +1301,11 @@ size_t ScTokenArray::GetHash() const
size_t nHash = 1;
OpCode eOp;
StackVar eType;
- const FormulaToken* p;
+ const ScToken* p;
sal_uInt16 n = std::min<sal_uInt16>(nLen, 20);
for (sal_uInt16 i = 0; i < n; ++i)
{
- p = pCode[i];
+ p = static_cast<const ScToken*>(pCode[i]);
eOp = p->GetOpCode();
if (eOp == ocPush)
{
@@ -1314,8 +1334,22 @@ size_t ScTokenArray::GetHash() const
nHash += (aHasher(rStr) << i);
continue;
}
+ case svSingleRef:
+ {
+ size_t nVal = HashSingleRef(p->GetSingleRef());
+ nHash += (nVal << i);
+ continue;
+ }
+ case svDoubleRef:
+ {
+ const ScComplexRefData& rRef = p->GetDoubleRef();
+ size_t nVal1 = HashSingleRef(rRef.Ref1);
+ size_t nVal2 = HashSingleRef(rRef.Ref2);
+ nHash += (nVal1 << i);
+ nHash += (nVal2 << i);
+ continue;
+ }
default:
- // TODO: Decide later if we should generate hash from references as well.
;
}
}
More information about the Libreoffice-commits
mailing list