Kaydet (Commit) b0c92c9d authored tarafından Michael Meeks's avatar Michael Meeks Kaydeden (comit) Kohei Yoshida

initial detection of similar formula runs.

Change-Id: I5659c46668a0d0a6ef67368a4e6bbf0d99a6a80e
üst a1e22bde
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <set> #include <set>
#include <vector> #include <vector>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/intrusive_ptr.hpp>
#include <tools/mempool.hxx> #include <tools/mempool.hxx>
#include <svl/listener.hxx> #include <svl/listener.hxx>
...@@ -331,6 +332,32 @@ private: ...@@ -331,6 +332,32 @@ private:
::std::vector<Item> maArray; ::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 { enum ScMatrixMode {
MM_NONE = 0, // No matrix formula MM_NONE = 0, // No matrix formula
MM_FORMULA = 1, // Upper left matrix formula cell MM_FORMULA = 1, // Upper left matrix formula cell
...@@ -349,6 +376,7 @@ private: ...@@ -349,6 +376,7 @@ private:
ScFormulaCell* pNext; ScFormulaCell* pNext;
ScFormulaCell* pPreviousTrack; ScFormulaCell* pPreviousTrack;
ScFormulaCell* pNextTrack; ScFormulaCell* pNextTrack;
ScFormulaCellGroupRef xGroup; // re-factoring hack - group of formulae we're part of.
sal_uLong nFormatIndex; // Number format set by calculation sal_uLong nFormatIndex; // Number format set by calculation
short nFormatType; // Number format type set by calculation short nFormatType; // Number format type set by calculation
sal_uInt16 nSeenInIteration; // Iteration cycle in which the cell was last encountered sal_uInt16 nSeenInIteration; // Iteration cycle in which the cell was last encountered
...@@ -558,6 +586,14 @@ public: ...@@ -558,6 +586,14 @@ public:
bool IsMultilineResult(); bool IsMultilineResult();
void MaybeInterpret(); 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 // Iterator for references in a formula cell
......
...@@ -108,10 +108,11 @@ class ScColumn ...@@ -108,10 +108,11 @@ class ScColumn
std::vector<ColEntry> maItems; std::vector<ColEntry> maItems;
ScAttrArray* pAttrArray; ScAttrArray* pAttrArray;
ScDocument* pDocument; ScDocument* pDocument;
bool bDirtyGroups; /// formula groups are dirty.
friend class ScDocument; // for FillInfo friend class ScDocument; // for FillInfo
friend class ScDocumentIterator; friend class ScDocumentIterator;
friend class ScValueIterator; friend class ScValueIterator;
friend class ScHorizontalValueIterator; friend class ScHorizontalValueIterator;
...@@ -146,6 +147,7 @@ public: ...@@ -146,6 +147,7 @@ public:
void ReserveSize( SCSIZE nSize ); void ReserveSize( SCSIZE nSize );
void SwapRow( SCROW nRow1, SCROW nRow2 ); void SwapRow( SCROW nRow1, SCROW nRow2 );
void SwapCell( SCROW nRow, ScColumn& rCol); void SwapCell( SCROW nRow, ScColumn& rCol);
void RebuildFormulaGroups();
bool HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const; bool HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const;
bool HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const; bool HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const;
......
...@@ -1687,6 +1687,104 @@ void ScFormulaCell::CompileColRowNameFormula() ...@@ -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: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
...@@ -85,7 +85,8 @@ ScColumn::ScColumn() : ...@@ -85,7 +85,8 @@ ScColumn::ScColumn() :
maScriptTypes(MAXROWCOUNT), maScriptTypes(MAXROWCOUNT),
nCol( 0 ), nCol( 0 ),
pAttrArray( NULL ), pAttrArray( NULL ),
pDocument( NULL ) pDocument( NULL ),
bDirtyGroups( true )
{ {
} }
...@@ -103,6 +104,7 @@ void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc) ...@@ -103,6 +104,7 @@ void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
nTab = nNewTab; nTab = nNewTab;
pDocument = pDoc; pDocument = pDoc;
pAttrArray = new ScAttrArray( nCol, nTab, pDocument ); pAttrArray = new ScAttrArray( nCol, nTab, pDocument );
bDirtyGroups = true;
} }
...@@ -851,6 +853,8 @@ void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2) ...@@ -851,6 +853,8 @@ void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
::std::swap( pCell1, pCell2 ); ::std::swap( pCell1, pCell2 );
} }
bDirtyGroups = true;
// from here: first cell (pCell1, nIndex1) exists always // from here: first cell (pCell1, nIndex1) exists always
ScAddress aPos1( nCol, nRow1, nTab ); ScAddress aPos1( nCol, nRow1, nTab );
...@@ -1010,6 +1014,8 @@ void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol) ...@@ -1010,6 +1014,8 @@ void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol)
return; return;
} }
bDirtyGroups = true;
// from here: own cell (pCell1, nIndex1) exists always // from here: own cell (pCell1, nIndex1) exists always
ScFormulaCell* pFmlaCell1 = (pCell1->GetCellType() == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0; ScFormulaCell* pFmlaCell1 = (pCell1->GetCellType() == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0;
...@@ -1129,6 +1135,8 @@ void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize ) ...@@ -1129,6 +1135,8 @@ void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
if ( i >= maItems.size() ) if ( i >= maItems.size() )
return ; return ;
bDirtyGroups = true;
bool bOldAutoCalc = pDocument->GetAutoCalc(); bool bOldAutoCalc = pDocument->GetAutoCalc();
pDocument->SetAutoCalc( false ); // avoid recalculations pDocument->SetAutoCalc( false ); // avoid recalculations
...@@ -1646,6 +1654,10 @@ void ScColumn::SwapCol(ScColumn& rCol) ...@@ -1646,6 +1654,10 @@ void ScColumn::SwapCol(ScColumn& rCol)
pAttrArray->SetCol(nCol); pAttrArray->SetCol(nCol);
rCol.pAttrArray->SetCol(rCol.nCol); rCol.pAttrArray->SetCol(rCol.nCol);
bool bDirty = bDirtyGroups;
bDirtyGroups = rCol.bDirtyGroups;
rCol.bDirtyGroups = bDirty;
SCSIZE i; SCSIZE i;
for (i = 0; i < maItems.size(); i++) for (i = 0; i < maItems.size(); i++)
{ {
...@@ -2008,6 +2020,8 @@ void ScColumn::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo ) ...@@ -2008,6 +2020,8 @@ void ScColumn::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
void ScColumn::UpdateCompile( bool bForceIfNameInUse ) void ScColumn::UpdateCompile( bool bForceIfNameInUse )
{ {
if ( !maItems.empty() ) if ( !maItems.empty() )
{
fprintf( stderr, "UpdateCompile - column !?\n" );
for (SCSIZE i = 0; i < maItems.size(); i++) for (SCSIZE i = 0; i < maItems.size(); i++)
{ {
ScFormulaCell* p = (ScFormulaCell*) maItems[i].pCell; ScFormulaCell* p = (ScFormulaCell*) maItems[i].pCell;
...@@ -2019,6 +2033,8 @@ void ScColumn::UpdateCompile( bool bForceIfNameInUse ) ...@@ -2019,6 +2033,8 @@ void ScColumn::UpdateCompile( bool bForceIfNameInUse )
Search( nRow, i ); // Listener deleted/inserted? Search( nRow, i ); // Listener deleted/inserted?
} }
} }
RebuildFormulaGroups();
}
} }
......
...@@ -1431,6 +1431,7 @@ void ScColumn::CellStorageModified() ...@@ -1431,6 +1431,7 @@ void ScColumn::CellStorageModified()
} }
cout << "-- end" << endl; cout << "-- end" << endl;
#endif #endif
RebuildFormulaGroups();
} }
void ScColumn::CopyScriptTypesToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol) const void ScColumn::CopyScriptTypesToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol) const
......
...@@ -120,6 +120,7 @@ void ScColumn::Insert( SCROW nRow, ScBaseCell* pNewCell ) ...@@ -120,6 +120,7 @@ void ScColumn::Insert( SCROW nRow, ScBaseCell* pNewCell )
ScAddress( nCol, nRow, nTab ), pNewCell ) ); ScAddress( nCol, nRow, nTab ), pNewCell ) );
} }
} }
bDirtyGroups = true;
} }
...@@ -133,6 +134,8 @@ void ScColumn::Insert( SCROW nRow, sal_uInt32 nNumberFormat, ScBaseCell* pCell ) ...@@ -133,6 +134,8 @@ void ScColumn::Insert( SCROW nRow, sal_uInt32 nNumberFormat, ScBaseCell* pCell )
short eNewType = pDocument->GetFormatTable()->GetType(nNumberFormat); short eNewType = pDocument->GetFormatTable()->GetType(nNumberFormat);
if (!pDocument->GetFormatTable()->IsCompatible(eOldType, eNewType)) if (!pDocument->GetFormatTable()->IsCompatible(eOldType, eNewType))
ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT, (sal_uInt32) nNumberFormat) ); ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT, (sal_uInt32) nNumberFormat) );
bDirtyGroups = true;
} }
...@@ -142,6 +145,7 @@ void ScColumn::Append( SCROW nRow, ScBaseCell* pCell ) ...@@ -142,6 +145,7 @@ void ScColumn::Append( SCROW nRow, ScBaseCell* pCell )
maItems.back().pCell = pCell; maItems.back().pCell = pCell;
maItems.back().nRow = nRow; maItems.back().nRow = nRow;
bDirtyGroups = true;
maTextWidths.set<unsigned short>(nRow, TEXTWIDTH_DIRTY); maTextWidths.set<unsigned short>(nRow, TEXTWIDTH_DIRTY);
maScriptTypes.set<unsigned short>(nRow, SC_SCRIPTTYPE_UNKNOWN); maScriptTypes.set<unsigned short>(nRow, SC_SCRIPTTYPE_UNKNOWN);
CellStorageModified(); CellStorageModified();
...@@ -173,6 +177,7 @@ void ScColumn::Delete( SCROW nRow ) ...@@ -173,6 +177,7 @@ void ScColumn::Delete( SCROW nRow )
} }
pCell->EndListeningTo( pDocument ); pCell->EndListeningTo( pDocument );
pCell->Delete(); pCell->Delete();
bDirtyGroups = true;
CellStorageModified(); CellStorageModified();
} }
...@@ -192,6 +197,7 @@ void ScColumn::DeleteAtIndex( SCSIZE nIndex ) ...@@ -192,6 +197,7 @@ void ScColumn::DeleteAtIndex( SCSIZE nIndex )
pCell->EndListeningTo( pDocument ); pCell->EndListeningTo( pDocument );
pCell->Delete(); pCell->Delete();
bDirtyGroups = true;
maTextWidths.set_empty(nRow, nRow); maTextWidths.set_empty(nRow, nRow);
maScriptTypes.set_empty(nRow, nRow); maScriptTypes.set_empty(nRow, nRow);
CellStorageModified(); CellStorageModified();
...@@ -228,6 +234,8 @@ void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize ) ...@@ -228,6 +234,8 @@ void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize )
sal_Bool bOldAutoCalc = pDocument->GetAutoCalc(); sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
pDocument->SetAutoCalc( false ); // Avoid calculating it multiple times pDocument->SetAutoCalc( false ); // Avoid calculating it multiple times
bDirtyGroups = true;
sal_Bool bFound=false; sal_Bool bFound=false;
SCROW nEndRow = nStartRow + nSize - 1; SCROW nEndRow = nStartRow + nSize - 1;
SCSIZE nStartIndex = 0; SCSIZE nStartIndex = 0;
...@@ -551,6 +559,8 @@ void ScColumn::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex, sal_uInt16 nDe ...@@ -551,6 +559,8 @@ void ScColumn::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex, sal_uInt16 nDe
(*aIt)->Delete(); (*aIt)->Delete();
} }
} }
bDirtyGroups = true;
} }
...@@ -598,6 +608,8 @@ void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag) ...@@ -598,6 +608,8 @@ void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag)
// Delete attributes just now // Delete attributes just now
if ((nDelFlag & IDF_ATTRIB) == IDF_ATTRIB) pAttrArray->DeleteArea( nStartRow, nEndRow ); if ((nDelFlag & IDF_ATTRIB) == IDF_ATTRIB) pAttrArray->DeleteArea( nStartRow, nEndRow );
else if ((nDelFlag & IDF_ATTRIB) != 0) pAttrArray->DeleteHardAttr( nStartRow, nEndRow ); else if ((nDelFlag & IDF_ATTRIB) != 0) pAttrArray->DeleteHardAttr( nStartRow, nEndRow );
bDirtyGroups = true;
} }
...@@ -1984,4 +1996,82 @@ xub_StrLen ScColumn::GetMaxNumberStringLen( ...@@ -1984,4 +1996,82 @@ xub_StrLen ScColumn::GetMaxNumberStringLen(
return nStringLen; 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: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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