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

Michael Meeks michael.meeks at suse.com
Mon Mar 18 06:27:01 PDT 2013


 sc/inc/cell.hxx                 |   36 ++++++++++++++
 sc/inc/column.hxx               |    8 ++-
 sc/source/core/data/cell2.cxx   |   98 ++++++++++++++++++++++++++++++++++++++++
 sc/source/core/data/column.cxx  |   18 ++++++-
 sc/source/core/data/column2.cxx |    1 
 sc/source/core/data/column3.cxx |   90 ++++++++++++++++++++++++++++++++++++
 6 files changed, 247 insertions(+), 4 deletions(-)

New commits:
commit d1306fe90b015251b8ada38b9706271ad6bac268
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Mon Mar 18 13:25:43 2013 +0000

    initial detection of similar formula runs.
    
    Change-Id: I5659c46668a0d0a6ef67368a4e6bbf0d99a6a80e

diff --git a/sc/inc/cell.hxx b/sc/inc/cell.hxx
index 4f09baa..d9fb42a 100644
--- a/sc/inc/cell.hxx
+++ b/sc/inc/cell.hxx
@@ -25,6 +25,7 @@
 #include <set>
 #include <vector>
 #include <boost/shared_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
 
 #include <tools/mempool.hxx>
 #include <svl/listener.hxx>
@@ -331,6 +332,32 @@ private:
     ::std::vector<Item> maArray;
 };
 
+struct ScSimilarFormulaDelta;
+
+struct SC_DLLPUBLIC ScFormulaCellGroup
+{
+    sal_Int32              mnRefCount;
+    ScSimilarFormulaDelta *mpDelta;  // difference between items in column
+    sal_Int32              mnStart;  // Start offset of that cell
+    sal_Int32              mnLength; // How many of these do we have ?
+
+    ScFormulaCellGroup();
+    ~ScFormulaCellGroup();
+
+    bool IsCompatible( ScSimilarFormulaDelta *pDelta );
+};
+inline void intrusive_ptr_add_ref(ScFormulaCellGroup *p)
+{
+    p->mnRefCount++;
+}
+inline void intrusive_ptr_release(ScFormulaCellGroup *p)
+{
+    if( --p->mnRefCount == 0 )
+        delete p;
+}
+
+typedef ::boost::intrusive_ptr<ScFormulaCellGroup> ScFormulaCellGroupRef;
+
 enum ScMatrixMode {
     MM_NONE      = 0,                   // No matrix formula
     MM_FORMULA   = 1,                   // Upper left matrix formula cell
@@ -349,6 +376,7 @@ private:
     ScFormulaCell*  pNext;
     ScFormulaCell*  pPreviousTrack;
     ScFormulaCell*  pNextTrack;
+    ScFormulaCellGroupRef xGroup;       // re-factoring hack - group of formulae we're part of.
     sal_uLong       nFormatIndex;       // Number format set by calculation
     short           nFormatType;        // Number format type set by calculation
     sal_uInt16      nSeenInIteration;   // Iteration cycle in which the cell was last encountered
@@ -558,6 +586,14 @@ public:
     bool            IsMultilineResult();
 
     void            MaybeInterpret();
+
+    // Temporary formula cell grouping API
+    ScFormulaCellGroupRef  GetCellGroup()
+        { return xGroup; }
+    void                   SetCellGroup( const ScFormulaCellGroupRef &xRef )
+        { xGroup = xRef; }
+    ScSimilarFormulaDelta *BuildDeltaTo( ScFormulaCell *pOther );
+    void                   ReleaseDelta( ScSimilarFormulaDelta *pDelta );
 };
 
 //          Iterator for references in a formula cell
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index f5a7802..4ec4f29 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -108,10 +108,11 @@ class ScColumn
 
     std::vector<ColEntry> maItems;
 
-    ScAttrArray*       pAttrArray;
-    ScDocument*                pDocument;
+    ScAttrArray*          pAttrArray;
+    ScDocument*           pDocument;
+    bool                  bDirtyGroups;     /// formula groups are dirty.
 
-friend class ScDocument;                                       // for FillInfo
+friend class ScDocument;                    // for FillInfo
 friend class ScDocumentIterator;
 friend class ScValueIterator;
 friend class ScHorizontalValueIterator;
@@ -146,6 +147,7 @@ public:
     void ReserveSize( SCSIZE nSize );
     void        SwapRow( SCROW nRow1, SCROW nRow2 );
     void        SwapCell( SCROW nRow, ScColumn& rCol);
+    void        RebuildFormulaGroups();
 
     bool        HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const;
     bool    HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const;
diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx
index 28c574c..4cb4eb8 100644
--- a/sc/source/core/data/cell2.cxx
+++ b/sc/source/core/data/cell2.cxx
@@ -1687,6 +1687,104 @@ void ScFormulaCell::CompileColRowNameFormula()
     }
 }
 
+struct ScSimilarFormulaDelta : std::vector< size_t >
+{
+    // we really want to be a lot more descriptive than this
+    bool IsCompatible( ScSimilarFormulaDelta *pDelta )
+    {
+        if ( size() != pDelta->size() )
+            return false;
+        for ( size_t i = 0; i < size(); i++ )
+        {
+            if ( (*this)[ i ] != (*pDelta)[ i ] )
+                return false;
+        }
+        return true;
+    }
+
+    void push_delta( const ScSingleRefData& a, const ScSingleRefData& b )
+    {
+        push_back( b.nCol - a.nCol );
+        push_back( b.nRow - a.nRow );
+        push_back( b.nTab - a.nTab );
+    }
+};
+
+bool ScFormulaCellGroup::IsCompatible( ScSimilarFormulaDelta *pDelta )
+{
+    return pDelta && mpDelta && mpDelta->IsCompatible( pDelta );
+}
+
+/// compare formulae tokens and build a series of deltas describing
+/// the difference - ie. the result, when added to this
+/// formulae should produce pOther
+ScSimilarFormulaDelta *ScFormulaCell::BuildDeltaTo( ScFormulaCell *pOtherCell )
+{
+
+// FIXME: TODO - M1
+//    if ( kohei_comparison_hash_not_equal( mnHash, pOther->mnHash )
+//       return NULL;
+
+    FormulaToken **pThis = pCode->GetCode();
+    sal_uInt16     pThisLen = pCode->GetCodeLen();
+    FormulaToken **pOther = pOtherCell->pCode->GetCode();
+    sal_uInt16     pOtherLen = pOtherCell->pCode->GetCodeLen();
+
+    if ( !pThis || !pOther )
+    {
+        fprintf( stderr, "no compiled code for cells !" );
+        return NULL;
+    }
+
+    if ( pThisLen != pOtherLen )
+    {
+        fprintf( stderr, "different length formulae !" );
+        return NULL;
+    }
+
+    // check we are basically the same function
+    for ( sal_uInt16 i = 0; i < pThisLen; i++ )
+    {
+        if ( pThis[ i ]->GetType() != pOther[ i ]->GetType() ||
+             pThis[ i ]->GetOpCode() != pOther[ i ]->GetOpCode() ||
+             pThis[ i ]->GetParamCount() != pOther[ i ]->GetParamCount() )
+        {
+            fprintf( stderr, "Incompatible type, op-code or param counts\n" );
+            return NULL;
+        }
+        if( pThis[ i ]->GetType() == formula::svMatrix ||
+            pOther[ i ]->GetType() == formula::svMatrix )
+        {
+            fprintf( stderr, "Ignoring matrix formulae for now\n" );
+            return NULL;
+        }
+    }
+
+    fprintf( stderr, "matching formulae !\n" );
+    ScSimilarFormulaDelta *pDelta = new ScSimilarFormulaDelta();
+
+    for ( sal_uInt16 i = 0; i < pThisLen; i++ )
+    {
+        ScToken *pThisTok = static_cast< ScToken * >( pThis[ i ] );
+        ScToken *pOtherTok = static_cast< ScToken * >( pOther[ i ] );
+
+        const ScSingleRefData& aThisRef = pThisTok->GetSingleRef();
+        const ScSingleRefData& aOtherRef = pOtherTok->GetSingleRef();
+        pDelta->push_delta( aThisRef, aOtherRef );
+
+        const ScSingleRefData& aThisRef2 = pThisTok->GetSingleRef2();
+        const ScSingleRefData& aOtherRef2 = pOtherTok->GetSingleRef2();
+        pDelta->push_delta( aThisRef2, aOtherRef2 );
+    }
+
+    return pDelta;
+}
+
+void ScFormulaCell::ReleaseDelta( ScSimilarFormulaDelta *pDelta )
+{
+    delete pDelta;
+}
+
 // ============================================================================
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index e8a39ad..d8c3bcd 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -85,7 +85,8 @@ ScColumn::ScColumn() :
     maScriptTypes(MAXROWCOUNT),
     nCol( 0 ),
     pAttrArray( NULL ),
-    pDocument( NULL )
+    pDocument( NULL ),
+    bDirtyGroups( true )
 {
 }
 
@@ -103,6 +104,7 @@ void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
     nTab = nNewTab;
     pDocument = pDoc;
     pAttrArray = new ScAttrArray( nCol, nTab, pDocument );
+    bDirtyGroups = true;
 }
 
 
@@ -851,6 +853,8 @@ void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
         ::std::swap( pCell1, pCell2 );
     }
 
+    bDirtyGroups = true;
+
     // from here: first cell (pCell1, nIndex1) exists always
 
     ScAddress aPos1( nCol, nRow1, nTab );
@@ -1010,6 +1014,8 @@ void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol)
         return;
     }
 
+    bDirtyGroups = true;
+
     // from here: own cell (pCell1, nIndex1) exists always
 
     ScFormulaCell* pFmlaCell1 = (pCell1->GetCellType() == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0;
@@ -1129,6 +1135,8 @@ void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
     if ( i >= maItems.size() )
         return ;
 
+    bDirtyGroups = true;
+
     bool bOldAutoCalc = pDocument->GetAutoCalc();
     pDocument->SetAutoCalc( false );    // avoid recalculations
 
@@ -1646,6 +1654,10 @@ void ScColumn::SwapCol(ScColumn& rCol)
     pAttrArray->SetCol(nCol);
     rCol.pAttrArray->SetCol(rCol.nCol);
 
+    bool bDirty = bDirtyGroups;
+    bDirtyGroups = rCol.bDirtyGroups;
+    rCol.bDirtyGroups = bDirty;
+
     SCSIZE i;
     for (i = 0; i < maItems.size(); i++)
     {
@@ -2008,6 +2020,8 @@ void ScColumn::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
 void ScColumn::UpdateCompile( bool bForceIfNameInUse )
 {
     if ( !maItems.empty() )
+    {
+        fprintf( stderr, "UpdateCompile - column !?\n" );
         for (SCSIZE i = 0; i < maItems.size(); i++)
         {
             ScFormulaCell* p = (ScFormulaCell*) maItems[i].pCell;
@@ -2019,6 +2033,8 @@ void ScColumn::UpdateCompile( bool bForceIfNameInUse )
                     Search( nRow, i );      // Listener deleted/inserted?
             }
         }
+        RebuildFormulaGroups();
+    }
 }
 
 
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 3301542..81f65d4 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1431,6 +1431,7 @@ void ScColumn::CellStorageModified()
     }
     cout << "-- end" << endl;
 #endif
+    RebuildFormulaGroups();
 }
 
 void ScColumn::CopyScriptTypesToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol) const
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 28340a2..633143d 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -120,6 +120,7 @@ void ScColumn::Insert( SCROW nRow, ScBaseCell* pNewCell )
                     ScAddress( nCol, nRow, nTab ), pNewCell ) );
         }
     }
+    bDirtyGroups = true;
 }
 
 
@@ -133,6 +134,8 @@ void ScColumn::Insert( SCROW nRow, sal_uInt32 nNumberFormat, ScBaseCell* pCell )
     short eNewType = pDocument->GetFormatTable()->GetType(nNumberFormat);
     if (!pDocument->GetFormatTable()->IsCompatible(eOldType, eNewType))
         ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT, (sal_uInt32) nNumberFormat) );
+
+    bDirtyGroups = true;
 }
 
 
@@ -142,6 +145,7 @@ void ScColumn::Append( SCROW nRow, ScBaseCell* pCell )
     maItems.back().pCell = pCell;
     maItems.back().nRow  = nRow;
 
+    bDirtyGroups = true;
     maTextWidths.set<unsigned short>(nRow, TEXTWIDTH_DIRTY);
     maScriptTypes.set<unsigned short>(nRow, SC_SCRIPTTYPE_UNKNOWN);
     CellStorageModified();
@@ -173,6 +177,7 @@ void ScColumn::Delete( SCROW nRow )
         }
         pCell->EndListeningTo( pDocument );
         pCell->Delete();
+        bDirtyGroups = true;
 
         CellStorageModified();
     }
@@ -192,6 +197,7 @@ void ScColumn::DeleteAtIndex( SCSIZE nIndex )
     pCell->EndListeningTo( pDocument );
     pCell->Delete();
 
+    bDirtyGroups = true;
     maTextWidths.set_empty(nRow, nRow);
     maScriptTypes.set_empty(nRow, nRow);
     CellStorageModified();
@@ -228,6 +234,8 @@ void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize )
     sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
     pDocument->SetAutoCalc( false ); // Avoid calculating it multiple times
 
+    bDirtyGroups = true;
+
     sal_Bool bFound=false;
     SCROW nEndRow = nStartRow + nSize - 1;
     SCSIZE nStartIndex = 0;
@@ -551,6 +559,8 @@ void ScColumn::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex, sal_uInt16 nDe
             (*aIt)->Delete();
         }
     }
+
+    bDirtyGroups = true;
 }
 
 
@@ -598,6 +608,8 @@ void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag)
     // Delete attributes just now
     if ((nDelFlag & IDF_ATTRIB) == IDF_ATTRIB) pAttrArray->DeleteArea( nStartRow, nEndRow );
     else if ((nDelFlag & IDF_ATTRIB) != 0) pAttrArray->DeleteHardAttr( nStartRow, nEndRow );
+
+    bDirtyGroups = true;
 }
 
 
@@ -1984,4 +1996,82 @@ xub_StrLen ScColumn::GetMaxNumberStringLen(
     return nStringLen;
 }
 
+
+ScFormulaCellGroup::ScFormulaCellGroup()
+{
+}
+
+ScFormulaCellGroup::~ScFormulaCellGroup()
+{
+}
+
+// Very[!] slow way to look for and merge contiguous runs
+// of similar formulae into a formulagroup
+void ScColumn::RebuildFormulaGroups()
+{
+    if ( maItems.empty() )
+        return;
+
+    // clear previous groups
+    ScFormulaCellGroupRef xNone;
+    for (size_t i = 0; i < maItems.size(); i++)
+    {
+        ColEntry &rCur = maItems[ i ];
+        if ( rCur.pCell && rCur.pCell->GetCellType() == CELLTYPE_FORMULA )
+            static_cast<ScFormulaCell *>( rCur.pCell )->SetCellGroup( xNone );
+    }
+
+    // re-build groups
+    for (size_t i = 1; i < maItems.size(); i++)
+    {
+        ColEntry &rCur = maItems[ i ];
+        ColEntry &rPrev = maItems[ i - 1 ];
+        if ( ( rPrev.nRow != rCur.nRow - 1 ) ||               // not contiguous
+             !rCur.pCell || !rPrev.pCell ||                   // paranoia
+             rCur.pCell->GetCellType() != CELLTYPE_FORMULA || // not formulae
+             rPrev.pCell->GetCellType() != CELLTYPE_FORMULA )
+            continue;
+
+        // see if these formulae are similar
+        ScFormulaCell *pCur = static_cast< ScFormulaCell *>( rCur.pCell );
+        ScFormulaCell *pPrev = static_cast< ScFormulaCell *>( rPrev.pCell );
+
+        fprintf( stderr, "column has contiguous formulae\n" );
+        ScSimilarFormulaDelta *pDelta = pPrev->BuildDeltaTo( pCur );
+
+        if ( !pDelta )
+        {
+            // not similar
+            pCur->SetCellGroup( xNone );
+            continue;
+        }
+
+        ScFormulaCellGroupRef xGroup = pPrev->GetCellGroup();
+        if ( !xGroup.get() )
+        {
+            // create a new group ...
+            ScFormulaCellGroup *pGroup = new ScFormulaCellGroup();
+            pGroup->mpDelta = pDelta;
+            pGroup->mnStart = i - 1;
+            pGroup->mnLength = 2;
+
+            xGroup.reset( pGroup );
+            pCur->SetCellGroup( xGroup );
+            pPrev->SetCellGroup( xGroup );
+        }
+        else if ( xGroup->IsCompatible( pDelta ) )
+        {
+            // we are a compatible extension - extend the group
+            pCur->SetCellGroup( xGroup );
+            xGroup->mnLength++;
+            pCur->ReleaseDelta( pDelta );
+        }
+        else
+        {
+            fprintf( stderr, "unusual incompatible extension of formulae\n" );
+            pCur->ReleaseDelta( pDelta );
+        }
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list