[Libreoffice-commits] core.git: Branch 'feature/formula-core-rework' - formula/source sc/inc sc/qa sc/source

Kohei Yoshida kohei.yoshida at gmail.com
Mon Mar 18 11:19:04 PDT 2013


 formula/source/core/api/token.cxx |   49 +++++++++++++++++++++++++++++++++++
 sc/inc/column.hxx                 |    2 +
 sc/inc/document.hxx               |    4 ++
 sc/inc/table.hxx                  |    2 +
 sc/qa/unit/ucalc.cxx              |   52 ++++++++++++++++++++++++++++++++++++++
 sc/source/core/data/column2.cxx   |   18 +++++++++++++
 sc/source/core/data/document.cxx  |   13 +++++++++
 sc/source/core/data/table1.cxx    |    8 +++++
 8 files changed, 147 insertions(+), 1 deletion(-)

New commits:
commit e5406834fdeddd872a37cd183869f4c30d539a75
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Mar 18 14:19:52 2013 -0400

    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

diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx
index f331c1e..5a47d2e 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 4ec4f29..8147c06 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 4dc0602..7d23b89 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 6a0b078..2e8b697 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 ec94652..4d93eb1 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 3301542..ea4be5b 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 16d4277..ac5db47 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 38d705c..309674c 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);


More information about the Libreoffice-commits mailing list