diff options
Diffstat (limited to 'sc')
-rw-r--r-- | sc/inc/cell.hxx | 36 | ||||
-rw-r--r-- | sc/inc/column.hxx | 8 | ||||
-rw-r--r-- | sc/source/core/data/cell2.cxx | 98 | ||||
-rw-r--r-- | sc/source/core/data/column.cxx | 18 | ||||
-rw-r--r-- | sc/source/core/data/column2.cxx | 1 | ||||
-rw-r--r-- | sc/source/core/data/column3.cxx | 90 |
6 files changed, 247 insertions, 4 deletions
diff --git a/sc/inc/cell.hxx b/sc/inc/cell.hxx index 4f09baac5bad..d9fb42a8016a 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 f5a78029dfbe..4ec4f294182d 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 28c574c03e72..4cb4eb8fcae2 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 14bdc307bd7c..882b78eabfd6 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 330154226f14..81f65d4dbf3e 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 28340a2e0251..633143d4be6e 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: */ |