[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