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

Kohei Yoshida kohei.yoshida at gmail.com
Wed May 15 13:15:31 PDT 2013


 sc/inc/clipcontext.hxx              |   11 ++++++
 sc/inc/column.hxx                   |    8 ++++
 sc/inc/document.hxx                 |    4 ++
 sc/inc/mtvelements.hxx              |    9 +++++
 sc/inc/table.hxx                    |    4 ++
 sc/source/core/data/clipcontext.cxx |   57 +++++++++++++++++++++++++++++++--
 sc/source/core/data/column2.cxx     |   62 +++++++++++++++++++++++++++++++++++-
 sc/source/core/data/column3.cxx     |   54 ++++++++++++++++++-------------
 sc/source/core/data/document.cxx    |   23 +++++++++++++
 sc/source/core/data/table2.cxx      |    8 ++++
 10 files changed, 213 insertions(+), 27 deletions(-)

New commits:
commit 37d81a035a36b4d2352870b245d7fe758286647d
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Wed May 15 16:09:40 2013 -0400

    Keep track of current block position when pasting a range of cells.
    
    This avoids re-starting the search for insertion position in the cell
    text attribute array, on every single cell insertion. Instead of always
    searching from the first position, it starts the seaarch from the previous
    insertion position.
    
    This reduces the paste time from the previous 3.5 seconds to 1.7 seconds
    on my machine.
    
    Here is the scenario.
    
    1) Put =A1 in B1, and leave B2 empty.
    2) Select B1:B2 and copy it via Ctrl-C.
    3) Select B3:B50000, and paste via Ctrl-V.
    
    Because of the empty cells interspersing the destination range, this makes
    the data array highly partitioned, which makes the position lookup very
    very expensive without the position hint.
    
    Still, I was hoping the duration would become a fraction of a second. 1.7
    seconds still seems a bit too slow...
    
    Change-Id: I7742ce7e22935b6d0e082e4569d53dbd2072c4e5

diff --git a/sc/inc/clipcontext.hxx b/sc/inc/clipcontext.hxx
index ffe66b0..8b1f261 100644
--- a/sc/inc/clipcontext.hxx
+++ b/sc/inc/clipcontext.hxx
@@ -13,12 +13,20 @@
 #include "address.hxx"
 #include "mtvelements.hxx"
 
+#include <vector>
+#include <boost/unordered_map.hpp>
+
 class ScDocument;
 
 namespace sc {
 
 class CopyFromClipContext
 {
+    typedef boost::unordered_map<SCCOL, ColumnBlockPosition> ColumnsType;
+    typedef std::vector<ColumnsType> TablesType;
+
+    TablesType maTables;
+
     ScDocument* mpRefUndoDoc;
     ScDocument* mpClipDoc;
     sal_uInt16  mnInsertFlag;
@@ -33,10 +41,13 @@ public:
         ScDocument* pRefUndoDoc, ScDocument* pClipDoc, sal_uInt16 nInsertFlag,
         bool bAsLink, bool bSkipAttrForEmptyCells);
 
+    bool initBlockPositions(ScDocument& rDoc, SCCOL nCol1, SCCOL nCol2);
     void setTabRange(SCTAB nStart, SCTAB nEnd);
 
     ~CopyFromClipContext();
 
+    ColumnBlockPosition* getBlockPosition(SCTAB nTab, SCCOL nCol);
+
     ScDocument* getUndoDoc();
     ScDocument* getClipDoc();
     sal_uInt16 getInsertFlag() const;
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 60f766d..edf362f 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -39,6 +39,7 @@ namespace sc {
     struct FormulaGroupContext;
     class EndListeningContext;
     class CopyFromClipContext;
+    struct ColumnBlockPosition;
 }
 
 class Fraction;
@@ -160,8 +161,10 @@ public:
     bool    Search( SCROW nRow, SCSIZE& nIndex ) const;
     ScBaseCell* GetCell( SCROW nRow ) const;
     ScRefCellValue GetCellValue( SCROW nRow ) const;
+    void Insert( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScBaseCell* pCell );
     void        Insert( SCROW nRow, ScBaseCell* pCell );
     void        Insert( SCROW nRow, sal_uInt32 nFormatIndex, ScBaseCell* pCell );
+    void Append( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScBaseCell* pCell );
     void        Append( SCROW nRow, ScBaseCell* pCell );
     void        Delete( SCROW nRow );
     void        DeleteAtIndex( SCSIZE nIndex );
@@ -215,6 +218,7 @@ public:
     void CopyToClip(SCROW nRow1, SCROW nRow2, ScColumn& rColumn, bool bKeepScenarioFlags) const;
     void CopyStaticToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol);
     void CopyCellToDocument( SCROW nSrcRow, SCROW nDestRow, ScColumn& rDestCol );
+    bool InitBlockPosition( sc::ColumnBlockPosition& rBlockPos );
     void CopyFromClip(
         sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, long nDy, ScColumn& rColumn );
 
@@ -480,7 +484,9 @@ private:
 
     void CopyCellTextAttrsToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol) const;
 
-    void SetCell(SCROW nRow, ScBaseCell* pNewCell);
+    void SetCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScBaseCell* pNewCell );
+    void SetCell( SCROW nRow, ScBaseCell* pNewCell );
+    void PostSetCell( SCROW nRow, ScBaseCell* pNewCell );
 };
 
 
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 4d71471..c511cf0 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -51,6 +51,7 @@ namespace sc {
     struct FormulaGroupContext;
     class EndListeningContext;
     class CopyFromClipContext;
+    struct ColumnBlockPosition;
 }
 class SvxFontItem;
 
@@ -1140,6 +1141,9 @@ public:
 
     void            CopyTabToClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                                 SCTAB nTab, ScDocument* pClipDoc = NULL);
+
+    bool InitColumnBlockPosition( sc::ColumnBlockPosition& rBlokPos, SCTAB nTab, SCCOL nCol );
+
     void CopyBlockFromClip(
         sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
         const ScMarkData& rMark, SCsCOL nDx, SCsROW nDy );
diff --git a/sc/inc/mtvelements.hxx b/sc/inc/mtvelements.hxx
index 16113d5..b21f7c7 100644
--- a/sc/inc/mtvelements.hxx
+++ b/sc/inc/mtvelements.hxx
@@ -65,6 +65,15 @@ typedef mdds::multi_type_vector<BCBlkFunc> BroadcasterStoreType;
 typedef mdds::mtv::custom_block_func1<sc::element_type_celltextattr, sc::custom_celltextattr_block> CTAttrFunc;
 typedef mdds::multi_type_vector<CTAttrFunc> CellTextAttrStoreType;
 
+/**
+ * Store position data for column array storage.
+ */
+struct ColumnBlockPosition
+{
+    BroadcasterStoreType::iterator miBroadcasterPos;
+    CellTextAttrStoreType::iterator miCellTextAttrPos;
+};
+
 }
 
 #endif
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 70fc1cf..00255fe 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -51,6 +51,7 @@ namespace sc {
     struct FormulaGroupContext;
     class EndListeningContext;
     class CopyFromClipContext;
+    struct ColumnBlockPosition;
 }
 
 class SfxItemSet;
@@ -384,6 +385,9 @@ public:
                            bool bKeepScenarioFlags, bool bCloneNoteCaptions);
     void CopyStaticToDocument(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScTable* pDestTab);
     void CopyCellToDocument( SCCOL nSrcCol, SCROW nSrcRow, SCCOL nDestCol, SCROW nDestRow, ScTable& rDestTab );
+
+    bool InitColumnBlockPosition( sc::ColumnBlockPosition& rBlockPos, SCCOL nCol );
+
     void CopyFromClip(
         sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
         SCsCOL nDx, SCsROW nDy, ScTable* pTable );
diff --git a/sc/source/core/data/clipcontext.cxx b/sc/source/core/data/clipcontext.cxx
index 5dcbddd..e3e66a2 100644
--- a/sc/source/core/data/clipcontext.cxx
+++ b/sc/source/core/data/clipcontext.cxx
@@ -8,6 +8,7 @@
  */
 
 #include "clipcontext.hxx"
+#include "document.hxx"
 
 namespace sc {
 
@@ -15,10 +16,50 @@ CopyFromClipContext::CopyFromClipContext(
     ScDocument* pRefUndoDoc, ScDocument* pClipDoc, sal_uInt16 nInsertFlag,
     bool bAsLink, bool bSkipAttrForEmptyCells) :
     mpRefUndoDoc(pRefUndoDoc), mpClipDoc(pClipDoc), mnInsertFlag(nInsertFlag),
-    mnTabStart(0), mnTabEnd(0),
+    mnTabStart(-1), mnTabEnd(-1),
     mbAsLink(bAsLink), mbSkipAttrForEmptyCells(bSkipAttrForEmptyCells) {}
 
-CopyFromClipContext::~CopyFromClipContext() {}
+CopyFromClipContext::~CopyFromClipContext()
+{
+}
+
+bool CopyFromClipContext::initBlockPositions(ScDocument& rDoc, SCCOL nCol1, SCCOL nCol2)
+{
+    if (mnTabStart < 0 || mnTabEnd < 0 || mnTabStart > mnTabEnd)
+        return false;
+
+    size_t nSize = mnTabEnd - mnTabStart + 1;
+    if (maTables.size() < nSize)
+        maTables.resize(nSize);
+
+    for (size_t i = 0; i < nSize; ++i)
+    {
+        SCTAB nTab = i + mnTabStart;
+        ColumnsType& rCols = maTables[i];
+        for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+        {
+            ColumnsType::iterator it = rCols.find(nCol);
+            if (it != rCols.end())
+                // This column has already been initialized. Skip it.
+                continue;
+
+            std::pair<ColumnsType::iterator,bool> r =
+                rCols.insert(
+                    ColumnsType::value_type(nCol, ColumnBlockPosition()));
+
+            if (!r.second)
+                // insertion failed.
+                return false;
+
+            it = r.first;
+
+            if (!rDoc.InitColumnBlockPosition(it->second, nTab, nCol))
+                return false;
+        }
+    }
+
+    return true;
+}
 
 void CopyFromClipContext::setTabRange(SCTAB nStart, SCTAB nEnd)
 {
@@ -26,6 +67,18 @@ void CopyFromClipContext::setTabRange(SCTAB nStart, SCTAB nEnd)
     mnTabEnd = nEnd;
 }
 
+ColumnBlockPosition* CopyFromClipContext::getBlockPosition(SCTAB nTab, SCCOL nCol)
+{
+    size_t nTabIndex = nTab - mnTabStart;
+    if (nTabIndex >= maTables.size())
+        return NULL;
+
+    ColumnsType& rCols = maTables[nTabIndex];
+    ColumnsType::iterator it = rCols.find(nCol);
+
+    return it == rCols.end() ? NULL : &it->second;
+}
+
 ScDocument* CopyFromClipContext::getUndoDoc()
 {
     return mpRefUndoDoc;
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 12b98aa..4400204 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1474,7 +1474,43 @@ void ScColumn::CopyCellTextAttrsToDocument(SCROW nRow1, SCROW nRow2, ScColumn& r
     }
 }
 
-void ScColumn::SetCell(SCROW nRow, ScBaseCell* pNewCell)
+void ScColumn::SetCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScBaseCell* pNewCell )
+{
+    bool bIsAppended = false;
+    if ( !maItems.empty() )
+    {
+        if (maItems.back().nRow < nRow)
+        {
+            Append(rBlockPos, nRow, pNewCell);
+            bIsAppended = true;
+        }
+    }
+    if (!bIsAppended)
+    {
+        SCSIZE nIndex;
+        if (Search(nRow, nIndex))
+        {
+            ScBaseCell* pOldCell = maItems[nIndex].pCell;
+            if ( pOldCell->GetCellType() == CELLTYPE_FORMULA && !pDocument->IsClipOrUndo() )
+                static_cast<ScFormulaCell*>(pOldCell)->EndListeningTo( pDocument );
+            pOldCell->Delete();
+            maItems[nIndex].pCell = pNewCell;
+        }
+        else
+        {
+            maItems.insert(maItems.begin() + nIndex, ColEntry());
+            maItems[nIndex].pCell = pNewCell;
+            maItems[nIndex].nRow  = nRow;
+        }
+
+        rBlockPos.miCellTextAttrPos =
+            maCellTextAttrs.set(rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
+
+        CellStorageModified();
+    }
+}
+
+void ScColumn::SetCell( SCROW nRow, ScBaseCell* pNewCell )
 {
     bool bIsAppended = false;
     if ( !maItems.empty() )
@@ -1508,6 +1544,30 @@ void ScColumn::SetCell(SCROW nRow, ScBaseCell* pNewCell)
     }
 }
 
+void ScColumn::PostSetCell( SCROW nRow, ScBaseCell* pNewCell )
+{
+    // When we insert from the Clipboard we still have wrong (old) References!
+    // First they are rewired in CopyBlockFromClip via UpdateReference and the
+    // we call StartListeningFromClip and BroadcastFromClip.
+    // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
+    // After Import we call CalcAfterLoad and in there Listening.
+    if ( !(pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc()) )
+    {
+        CellType eCellType = pNewCell->GetCellType();
+        if (eCellType == CELLTYPE_FORMULA)
+            static_cast<ScFormulaCell*>(pNewCell)->StartListeningTo(pDocument);
+
+        if (!pDocument->IsCalcingAfterLoad())
+        {
+            if ( eCellType == CELLTYPE_FORMULA )
+                ((ScFormulaCell*)pNewCell)->SetDirty();
+            else
+                pDocument->Broadcast(
+                    ScHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab)));
+        }
+    }
+}
+
 SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow)
 {
     return maBroadcasters.get<SvtBroadcaster*>(nRow);
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 0e15327..2939edb 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -78,30 +78,16 @@ void broadcastCells(ScDocument& rDoc, SCCOL nCol, SCROW nTab, const std::vector<
 
 }
 
+void ScColumn::Insert( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScBaseCell* pNewCell )
+{
+    SetCell(rBlockPos, nRow, pNewCell);
+    PostSetCell(nRow, pNewCell);
+}
+
 void ScColumn::Insert( SCROW nRow, ScBaseCell* pNewCell )
 {
     SetCell(nRow, pNewCell);
-
-    // When we insert from the Clipboard we still have wrong (old) References!
-    // First they are rewired in CopyBlockFromClip via UpdateReference and the
-    // we call StartListeningFromClip and BroadcastFromClip.
-    // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
-    // After Import we call CalcAfterLoad and in there Listening.
-    if ( !(pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc()) )
-    {
-        CellType eCellType = pNewCell->GetCellType();
-        if (eCellType == CELLTYPE_FORMULA)
-            static_cast<ScFormulaCell*>(pNewCell)->StartListeningTo(pDocument);
-
-        if (!pDocument->IsCalcingAfterLoad())
-        {
-            if ( eCellType == CELLTYPE_FORMULA )
-                ((ScFormulaCell*)pNewCell)->SetDirty();
-            else
-                pDocument->Broadcast(
-                    ScHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab)));
-        }
-    }
+    PostSetCell(nRow, pNewCell);
 }
 
 
@@ -111,6 +97,17 @@ void ScColumn::Insert( SCROW nRow, sal_uInt32 nNumberFormat, ScBaseCell* pCell )
     SetNumberFormat(nRow, nNumberFormat);
 }
 
+void ScColumn::Append( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScBaseCell* pCell )
+{
+    maItems.push_back(ColEntry());
+    maItems.back().pCell = pCell;
+    maItems.back().nRow  = nRow;
+
+    rBlockPos.miCellTextAttrPos =
+        maCellTextAttrs.set(rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
+
+    CellStorageModified();
+}
 
 void ScColumn::Append( SCROW nRow, ScBaseCell* pCell )
 {
@@ -122,7 +119,6 @@ void ScColumn::Append( SCROW nRow, ScBaseCell* pCell )
     CellStorageModified();
 }
 
-
 void ScColumn::Delete( SCROW nRow )
 {
     SCSIZE  nIndex;
@@ -561,6 +557,12 @@ ScFormulaCell* ScColumn::CreateRefCell( ScDocument* pDestDoc, const ScAddress& r
     return new ScFormulaCell( pDestDoc, rDestPos, &aArr );
 }
 
+bool ScColumn::InitBlockPosition( sc::ColumnBlockPosition& rBlockPos )
+{
+    rBlockPos.miBroadcasterPos = maBroadcasters.begin();
+    rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
+    return true;
+}
 
 //  rColumn = source
 //  nRow1, nRow2 = target position
@@ -662,7 +664,13 @@ void ScColumn::CopyFromClip(
                 rColumn.CreateRefCell(pDocument, aDestPos, i, rCxt.getInsertFlag()) :
                 rColumn.CloneCell(i, rCxt.getInsertFlag(), *pDocument, aDestPos);
             if (pNewCell)
-                Insert( aDestPos.Row(), pNewCell );
+            {
+                sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
+                if (p)
+                    Insert(*p, aDestPos.Row(), pNewCell);
+                else
+                    Insert(aDestPos.Row(), pNewCell);
+            }
         }
     }
 }
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 342499e..213b4f5 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2307,6 +2307,14 @@ void ScDocument::BroadcastFromClip( SCCOL nCol1, SCROW nRow1,
     }
 }
 
+bool ScDocument::InitColumnBlockPosition( sc::ColumnBlockPosition& rBlockPos, SCTAB nTab, SCCOL nCol )
+{
+    if (!TableExists(nTab))
+        return false;
+
+    return maTabs[nTab]->InitColumnBlockPosition(rBlockPos, nCol);
+}
+
 void ScDocument::CopyBlockFromClip(
     sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
     const ScMarkData& rMark, SCsCOL nDx, SCsROW nDy )
@@ -2518,6 +2526,18 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar
         pDestRanges = &aLocalRangeList;
     }
 
+    // Initialize column block positions first.
+    for (size_t nRange = 0; nRange < pDestRanges->size(); ++nRange)
+    {
+        const ScRange* pRange = (*pDestRanges)[nRange];
+        SCCOL nCol1 = pRange->aStart.Col();
+        SCCOL nCol2 = pRange->aEnd.Col();
+
+        if (!aCxt.initBlockPositions(*this, nCol1, nCol2))
+            // Initialization failed!
+            return;
+    }
+
     bInsertingFromOtherDoc = true;  // kein Broadcast/Listener aufbauen bei Insert
 
     SCCOL nClipStartCol = aClipRange.aStart.Col();
@@ -2651,6 +2671,9 @@ void ScDocument::CopyMultiRangeFromClip(
         SCsROW nDy = static_cast<SCsROW>(nBegRow - p->aStart.Row());
         SCCOL nCol2 = nCol1 + p->aEnd.Col() - p->aStart.Col();
 
+        if (!aCxt.initBlockPositions(*this, nCol1, nCol2))
+            return;
+
         SCROW nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
 
         if (!bSkipAttrForEmpty)
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 48f86ba..7f620dd 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -746,6 +746,14 @@ void ScTable::CopyConditionalFormat( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCRO
     }
 }
 
+bool ScTable::InitColumnBlockPosition( sc::ColumnBlockPosition& rBlockPos, SCCOL nCol )
+{
+    if (!ValidCol(nCol))
+        return false;
+
+    return aCol[nCol].InitBlockPosition(rBlockPos);
+}
+
 void ScTable::CopyFromClip(
     sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
     SCsCOL nDx, SCsROW nDy, ScTable* pTable )


More information about the Libreoffice-commits mailing list