Kaydet (Commit) aed58c04 authored tarafından Kohei Yoshida's avatar Kohei Yoshida

Embed reference tokens in the generated hash values.

Also make the test code a bit easier to extend.

Change-Id: Ib4e381cc139231884999c9d0dc9f51201e11f807
üst 198a7229
...@@ -1196,47 +1196,47 @@ void Test::testFormulaGrouping() ...@@ -1196,47 +1196,47 @@ void Test::testFormulaGrouping()
ScAddress aPos1(0,0,0), aPos2(1,0,0); ScAddress aPos1(0,0,0), aPos2(1,0,0);
// simplest cases. struct {
m_pDoc->SetString(aPos1, "=1"); const char* pFormula1; const char* pFormula2; bool bEqual;
size_t nHashVal1 = m_pDoc->GetFormulaHash(aPos1); } aTests[] = {
m_pDoc->SetString(aPos2, "=2"); { "=1", "=2", false }, // different constants
size_t nHashVal2 = m_pDoc->GetFormulaHash(aPos2); { "=SUM(1;2;3;4;5)", "=AVERAGE(1;2;3;4;5)", false }, // different functions
CPPUNIT_ASSERT_MESSAGE("These hashes should differ.", nHashVal1 != nHashVal2); { "=C2*3", "=D2*3", true }, // relative references
{ "=C2*3", "=D2*4", false }, // different constants
// different cell functions. { "=C2*4", "=D2*4", true }, // relative references
aPos1.IncRow(); { "=3*4*5", "=3*4*\"foo\"", false }, // numeric vs string constants
aPos2.IncRow(); { "=$C3/2", "=$C3/2", true }, // absolute column references
m_pDoc->SetString(aPos1, "=SUM(1;2;3;4;5)"); { "=C$3/2", "=D$3/2", true }, // absolute row references
m_pDoc->SetString(aPos2, "=AVERAGE(1;2;3;4;5)"); { "=$E$30/2", "=$E$30/2", true }, // absolute references
nHashVal1 = m_pDoc->GetFormulaHash(aPos1); { "=X20", "=$X$20", false }, // absolute vs relative
nHashVal2 = m_pDoc->GetFormulaHash(aPos2); { "=X20", "=X$20", false }, // absolute vs relative
CPPUNIT_ASSERT_MESSAGE("These hashes should differ.", nHashVal1 != nHashVal2); { "=X20", "=$X20", false }, // absolute vs relative
{ "=X$20", "=$X20", false }, // column absolute vs row absolute
// same relative references. };
aPos1.IncRow();
aPos2.IncRow(); for (size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i)
m_pDoc->SetString(aPos1, "=A2*3"); {
m_pDoc->SetString(aPos2, "=B2*3"); m_pDoc->SetString(aPos1, OUString::createFromAscii(aTests[i].pFormula1));
nHashVal1 = m_pDoc->GetFormulaHash(aPos1); m_pDoc->SetString(aPos2, OUString::createFromAscii(aTests[i].pFormula2));
nHashVal2 = m_pDoc->GetFormulaHash(aPos2); size_t nHashVal1 = m_pDoc->GetFormulaHash(aPos1);
CPPUNIT_ASSERT_MESSAGE("These hashes should be equal.", nHashVal1 == nHashVal2); size_t nHashVal2 = m_pDoc->GetFormulaHash(aPos2);
m_pDoc->SetString(aPos2, "=B2*4"); // Change the constant. std::ostringstream os;
nHashVal2 = m_pDoc->GetFormulaHash(aPos2); os << "(expr1:" << aTests[i].pFormula1 << "; expr2:" << aTests[i].pFormula2 << ")";
CPPUNIT_ASSERT_MESSAGE("These hashes should differ.", nHashVal1 != nHashVal2); if (aTests[i].bEqual)
{
m_pDoc->SetString(aPos1, "=A2*4"); // Change the constant again to make it "equal". os << " Error: these hashes should be equal." << endl;
nHashVal1 = m_pDoc->GetFormulaHash(aPos1); CPPUNIT_ASSERT_MESSAGE(os.str().c_str(), nHashVal1 == nHashVal2);
CPPUNIT_ASSERT_MESSAGE("These hashes should be equal.", nHashVal1 == nHashVal2); }
else
// string constant vs numeric constant. {
aPos1.IncRow(); os << " Error: these hashes should differ." << endl;
aPos2.IncRow(); CPPUNIT_ASSERT_MESSAGE(os.str().c_str(), nHashVal1 != nHashVal2);
m_pDoc->SetString(aPos1, "=3*4*5"); }
m_pDoc->SetString(aPos2, "=3*4*\"foo\"");
nHashVal1 = m_pDoc->GetFormulaHash(aPos1); aPos1.IncRow();
nHashVal2 = m_pDoc->GetFormulaHash(aPos2); aPos2.IncRow();
CPPUNIT_ASSERT_MESSAGE("These hashes should differ.", nHashVal1 != nHashVal2); }
m_pDoc->DeleteTab(0); m_pDoc->DeleteTab(0);
} }
......
...@@ -1274,6 +1274,26 @@ bool ScTokenArray::ImplGetReference( ScRange& rRange, bool bValidOnly ) const ...@@ -1274,6 +1274,26 @@ bool ScTokenArray::ImplGetReference( ScRange& rRange, bool bValidOnly ) const
return bIs; 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 size_t ScTokenArray::GetHash() const
{ {
static OUStringHash aHasher; static OUStringHash aHasher;
...@@ -1281,11 +1301,11 @@ size_t ScTokenArray::GetHash() const ...@@ -1281,11 +1301,11 @@ size_t ScTokenArray::GetHash() const
size_t nHash = 1; size_t nHash = 1;
OpCode eOp; OpCode eOp;
StackVar eType; StackVar eType;
const FormulaToken* p; const ScToken* p;
sal_uInt16 n = std::min<sal_uInt16>(nLen, 20); sal_uInt16 n = std::min<sal_uInt16>(nLen, 20);
for (sal_uInt16 i = 0; i < n; ++i) for (sal_uInt16 i = 0; i < n; ++i)
{ {
p = pCode[i]; p = static_cast<const ScToken*>(pCode[i]);
eOp = p->GetOpCode(); eOp = p->GetOpCode();
if (eOp == ocPush) if (eOp == ocPush)
{ {
...@@ -1314,8 +1334,22 @@ size_t ScTokenArray::GetHash() const ...@@ -1314,8 +1334,22 @@ size_t ScTokenArray::GetHash() const
nHash += (aHasher(rStr) << i); nHash += (aHasher(rStr) << i);
continue; 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: default:
// TODO: Decide later if we should generate hash from references as well.
; ;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment