[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