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

Kohei Yoshida kohei.yoshida at gmail.com
Mon Jul 1 20:10:39 PDT 2013


 sc/inc/column.hxx                       |    6 -
 sc/inc/columnspanset.hxx                |   29 ++++-
 sc/inc/document.hxx                     |    3 
 sc/inc/table.hxx                        |    4 
 sc/source/core/data/column.cxx          |   54 +++++++++
 sc/source/core/data/columnspanset.cxx   |   84 ++++++++++++--
 sc/source/core/data/documen6.cxx        |    4 
 sc/source/core/data/document.cxx        |   17 ++
 sc/source/core/data/listenercontext.cxx |    4 
 sc/source/core/data/table3.cxx          |   31 +++++
 sc/source/core/tool/interpr1.cxx        |  183 +++++++++++++++++++++++++++++++-
 sc/source/core/tool/interpr5.cxx        |   24 ----
 12 files changed, 396 insertions(+), 47 deletions(-)

New commits:
commit 0f43bf6e5d43fe40111100765013e7a73d762b58
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jul 1 23:08:14 2013 -0400

    Re-implement the COUNT function for efficiency.
    
    By taking advantage of the block structure of the new cell storage.
    
    Change-Id: Ib953c14d364ccdff7df5caf70d57cec86189e3be

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 6cc3c4b..7ce53ad 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -44,6 +44,7 @@ namespace sc {
     class CopyToClipContext;
     class CopyToDocContext;
     class MixDocContext;
+    class ColumnSpanSet;
     struct ColumnBlockPosition;
     class SingleColumnSpanSet;
 }
@@ -116,7 +117,6 @@ class ScColumn
 
 friend class ScDocument;                    // for FillInfo
 friend class ScTable;
-friend class ScDocumentIterator;
 friend class ScValueIterator;
 friend class ScHorizontalValueIterator;
 friend class ScDBQueryDataIterator;
@@ -127,6 +127,7 @@ friend class ScHorizontalAttrIterator;
 friend class ScColumnTextWidthIterator;
 friend class ScDocumentImport;
 friend class sc::SingleColumnSpanSet;
+friend class sc::ColumnSpanSet;
 
     ScColumn(const ScColumn&); // disabled
     ScColumn& operator= (const ScColumn&); // disabled
@@ -242,6 +243,7 @@ public:
     void        SwapCol(ScColumn& rCol);
     void        MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol);
 
+    void MarkSubTotalCells( sc::ColumnSpanSet& rSet, SCROW nRow1, SCROW nRow2, bool bVal ) const;
 
     bool HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst);
 
@@ -407,6 +409,8 @@ public:
     void        ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark );
     void        ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark );
 
+    size_t CountNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const;
+
     long GetNeededSize(
         SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY,
         const Fraction& rZoomX, const Fraction& rZoomY,
diff --git a/sc/inc/columnspanset.hxx b/sc/inc/columnspanset.hxx
index 55c3f57..98533e2 100644
--- a/sc/inc/columnspanset.hxx
+++ b/sc/inc/columnspanset.hxx
@@ -16,8 +16,10 @@
 #include <mdds/flat_segment_tree.hpp>
 #include <boost/noncopyable.hpp>
 
+class ScDocument;
 class ScColumn;
 class ScMarkData;
+class ScRange;
 
 namespace sc {
 
@@ -30,12 +32,22 @@ struct ColumnBlockConstPosition;
 class ColumnSpanSet : boost::noncopyable
 {
     typedef mdds::flat_segment_tree<SCROW, bool> ColumnSpansType;
-    typedef std::vector<ColumnSpansType*> TableType;
+
+    struct ColumnType
+    {
+        ColumnSpansType maSpans;
+        ColumnSpansType::const_iterator miPos;
+
+        ColumnType(SCROW nStart, SCROW nEnd, bool bInit);
+    };
+
+    typedef std::vector<ColumnType*> TableType;
     typedef std::vector<TableType*> DocType;
 
     DocType maDoc;
+    bool mbInit;
 
-    ColumnSpansType& getColumnSpans(SCTAB nTab, SCCOL nCol);
+    ColumnType& getColumn(SCTAB nTab, SCCOL nCol);
 
 public:
     class Action
@@ -46,12 +58,23 @@ public:
         virtual void execute(const ScAddress& rPos, SCROW nLength, bool bVal) = 0;
     };
 
+    class ColumnAction
+    {
+    public:
+        virtual ~ColumnAction() = 0;
+        virtual void startColumn(ScColumn* pCol) = 0;
+        virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal) = 0;
+    };
+
+    ColumnSpanSet(bool bInit);
     ~ColumnSpanSet();
 
     void set(SCTAB nTab, SCCOL nCol, SCROW nRow, bool bVal);
     void set(SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2, bool bVal);
+    void set(const ScRange& rRange, bool bVal);
 
-    void executeFromTop(Action& ac) const;
+    void executeAction(Action& ac) const;
+    void executeColumnAction(ScDocument& rDoc, ColumnAction& ac) const;
 };
 
 /**
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 806fb77..4d41565 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -53,6 +53,7 @@ namespace sc {
     class StartListeningContext;
     class EndListeningContext;
     class CopyFromClipContext;
+    class ColumnSpanSet;
     struct ColumnBlockPosition;
 }
 class SvxFontItem;
@@ -228,6 +229,7 @@ friend class ScFormulaCell;
 friend class ScTable;
 friend struct ScRefCellValue;
 friend class ScDocumentImport;
+friend class sc::ColumnSpanSet;
 
     typedef ::std::vector<ScTable*> TableContainer;
 private:
@@ -1960,6 +1962,7 @@ public:
     void AddSubTotalCell(ScFormulaCell* pCell);
     void RemoveSubTotalCell(ScFormulaCell* pCell);
     void SetSubTotalCellsDirty(const ScRange& rDirtyRange);
+    void MarkSubTotalCells( sc::ColumnSpanSet& rSet, const ScRange& rRange, bool bVal ) const;
 
     sal_uInt16 GetTextWidth( const ScAddress& rPos ) const;
 
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 03060bb..a8d5128 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -57,6 +57,7 @@ namespace sc {
     class CopyToClipContext;
     class CopyToDocContext;
     class MixDocContext;
+    class ColumnSpanSet;
     struct ColumnBlockPosition;
 }
 
@@ -203,6 +204,7 @@ friend class ScDocAttrIterator;
 friend class ScAttrRectIterator;
 friend class ScColumnTextWidthIterator;
 friend class ScDocumentImport;
+friend class sc::ColumnSpanSet;
 
 public:
                 ScTable( ScDocument* pDoc, SCTAB nNewTab, const OUString& rNewName,
@@ -231,6 +233,8 @@ public:
     void        RemoveSubTotals( ScSubTotalParam& rParam );
     bool        DoSubTotals( ScSubTotalParam& rParam );
 
+    void MarkSubTotalCells( sc::ColumnSpanSet& rSet, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bVal ) const;
+
     const ScSheetEvents* GetSheetEvents() const              { return pSheetEvents; }
     void        SetSheetEvents( const ScSheetEvents* pNew );
 
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index aa82f4d1..2a59e7e 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -466,6 +466,33 @@ void ScColumn::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
     }
 }
 
+namespace {
+
+class NumericCellCounter
+{
+    size_t mnCount;
+public:
+    NumericCellCounter() : mnCount(0) {}
+
+    void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize)
+    {
+        if (rNode.type != sc::element_type_numeric)
+            return;
+
+        mnCount += nDataSize;
+    }
+
+    size_t getCount() const { return mnCount; }
+};
+
+}
+
+size_t ScColumn::CountNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const
+{
+    NumericCellCounter aFunc;
+    rPos.miCellPos = sc::ParseBlock(rPos.miCellPos, maCells, aFunc, nRow1, nRow2);
+    return aFunc.getCount();
+}
 
 void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark )
 {
@@ -2155,6 +2182,33 @@ void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
 
 namespace {
 
+class SubTotalCellPicker
+{
+    sc::ColumnSpanSet& mrSet;
+    SCTAB mnTab;
+    SCCOL mnCol;
+    bool mbVal;
+public:
+    SubTotalCellPicker(sc::ColumnSpanSet& rSet, SCTAB nTab, SCCOL nCol, bool bVal) :
+        mrSet(rSet), mnTab(nTab), mnCol(nCol), mbVal(bVal) {}
+
+    void operator() (size_t nRow, const ScFormulaCell* pCell)
+    {
+        if (pCell->IsSubTotal())
+            mrSet.set(mnTab, mnCol, nRow, mbVal);
+    }
+};
+
+}
+
+void ScColumn::MarkSubTotalCells( sc::ColumnSpanSet& rSet, SCROW nRow1, SCROW nRow2, bool bVal ) const
+{
+    SubTotalCellPicker aFunc(rSet, nTab, nCol, bVal);
+    sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
+}
+
+namespace {
+
 class UpdateRefOnCopy
 {
 protected:
diff --git a/sc/source/core/data/columnspanset.cxx b/sc/source/core/data/columnspanset.cxx
index 8bfb7fc..f8c7813 100644
--- a/sc/source/core/data/columnspanset.cxx
+++ b/sc/source/core/data/columnspanset.cxx
@@ -10,6 +10,8 @@
 #include "columnspanset.hxx"
 #include "stlalgorithm.hxx"
 #include "column.hxx"
+#include "table.hxx"
+#include "document.hxx"
 #include "mtvfunctions.hxx"
 #include "markdata.hxx"
 #include "rangelst.hxx"
@@ -18,9 +20,16 @@
 
 namespace sc {
 
+ColumnSpanSet::ColumnType::ColumnType(SCROW nStart, SCROW nEnd, bool bInit) :
+    maSpans(nStart, nEnd+1, bInit), miPos(maSpans.begin()) {}
+
 ColumnSpanSet::Action::~Action() {}
 void ColumnSpanSet::Action::startColumn(SCTAB /*nTab*/, SCCOL /*nCol*/) {}
 
+ColumnSpanSet::ColumnAction::~ColumnAction() {}
+
+ColumnSpanSet::ColumnSpanSet(bool bInit) : mbInit(bInit) {}
+
 ColumnSpanSet::~ColumnSpanSet()
 {
     DocType::iterator itTab = maDoc.begin(), itTabEnd = maDoc.end();
@@ -30,12 +39,12 @@ ColumnSpanSet::~ColumnSpanSet()
         if (!pTab)
             continue;
 
-        std::for_each(pTab->begin(), pTab->end(), ScDeleteObjectByPtr<ColumnSpansType>());
+        std::for_each(pTab->begin(), pTab->end(), ScDeleteObjectByPtr<ColumnType>());
         delete pTab;
     }
 }
 
-ColumnSpanSet::ColumnSpansType& ColumnSpanSet::getColumnSpans(SCTAB nTab, SCCOL nCol)
+ColumnSpanSet::ColumnType& ColumnSpanSet::getColumn(SCTAB nTab, SCCOL nCol)
 {
     if (static_cast<size_t>(nTab) >= maDoc.size())
         maDoc.resize(nTab+1, NULL);
@@ -48,7 +57,7 @@ ColumnSpanSet::ColumnSpansType& ColumnSpanSet::getColumnSpans(SCTAB nTab, SCCOL
         rTab.resize(nCol+1, NULL);
 
     if (!rTab[nCol])
-        rTab[nCol] = new ColumnSpansType(0, MAXROW+1, false);
+        rTab[nCol] = new ColumnType(0, MAXROW, mbInit);
 
     return *rTab[nCol];
 }
@@ -58,8 +67,8 @@ void ColumnSpanSet::set(SCTAB nTab, SCCOL nCol, SCROW nRow, bool bVal)
     if (!ValidTab(nTab) || !ValidCol(nCol) || !ValidRow(nRow))
         return;
 
-    ColumnSpansType& rCol = getColumnSpans(nTab, nCol);
-    rCol.insert_back(nRow, nRow+1, bVal);
+    ColumnType& rCol = getColumn(nTab, nCol);
+    rCol.miPos = rCol.maSpans.insert(rCol.miPos, nRow, nRow+1, bVal).first;
 }
 
 void ColumnSpanSet::set(SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2, bool bVal)
@@ -67,11 +76,23 @@ void ColumnSpanSet::set(SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2, bool b
     if (!ValidTab(nTab) || !ValidCol(nCol) || !ValidRow(nRow1) || !ValidRow(nRow2))
         return;
 
-    ColumnSpansType& rCol = getColumnSpans(nTab, nCol);
-    rCol.insert_back(nRow1, nRow2+1, bVal);
+    ColumnType& rCol = getColumn(nTab, nCol);
+    rCol.miPos = rCol.maSpans.insert(rCol.miPos, nRow1, nRow2+1, bVal).first;
 }
 
-void ColumnSpanSet::executeFromTop(Action& ac) const
+void ColumnSpanSet::set(const ScRange& rRange, bool bVal)
+{
+    for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
+    {
+        for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
+        {
+            ColumnType& rCol = getColumn(nTab, nCol);
+            rCol.miPos = rCol.maSpans.insert(rCol.miPos, rRange.aStart.Row(), rRange.aEnd.Row()+1, bVal).first;
+        }
+    }
+}
+
+void ColumnSpanSet::executeAction(Action& ac) const
 {
     for (size_t nTab = 0; nTab < maDoc.size(); ++nTab)
     {
@@ -85,8 +106,8 @@ void ColumnSpanSet::executeFromTop(Action& ac) const
                 continue;
 
             ac.startColumn(nTab, nCol);
-            ColumnSpansType& rCol = *rTab[nCol];
-            ColumnSpansType::const_iterator it = rCol.begin(), itEnd = rCol.end();
+            ColumnType& rCol = *rTab[nCol];
+            ColumnSpansType::const_iterator it = rCol.maSpans.begin(), itEnd = rCol.maSpans.end();
             SCROW nRow1, nRow2;
             nRow1 = it->first;
             bool bVal = it->second;
@@ -102,6 +123,49 @@ void ColumnSpanSet::executeFromTop(Action& ac) const
     }
 }
 
+void ColumnSpanSet::executeColumnAction(ScDocument& rDoc, ColumnAction& ac) const
+{
+    for (size_t nTab = 0; nTab < maDoc.size(); ++nTab)
+    {
+        if (!maDoc[nTab])
+            continue;
+
+        const TableType& rTab = *maDoc[nTab];
+        for (size_t nCol = 0; nCol < rTab.size(); ++nCol)
+        {
+            if (!rTab[nCol])
+                continue;
+
+            ScTable* pTab = rDoc.FetchTable(nTab);
+            if (!pTab)
+                continue;
+
+            if (!ValidCol(nCol))
+            {
+                // End the loop.
+                nCol = rTab.size();
+                continue;
+            }
+
+            ScColumn& rColumn = pTab->aCol[nCol];
+            ac.startColumn(&rColumn);
+            ColumnType& rCol = *rTab[nCol];
+            ColumnSpansType::const_iterator it = rCol.maSpans.begin(), itEnd = rCol.maSpans.end();
+            SCROW nRow1, nRow2;
+            nRow1 = it->first;
+            bool bVal = it->second;
+            for (++it; it != itEnd; ++it)
+            {
+                nRow2 = it->first-1;
+                ac.execute(nRow1, nRow2, bVal);
+
+                nRow1 = nRow2+1; // for the next iteration.
+                bVal = it->second;
+            }
+        }
+    }
+}
+
 namespace {
 
 class Scanner
diff --git a/sc/source/core/data/documen6.cxx b/sc/source/core/data/documen6.cxx
index a165f97..b9b8d5f 100644
--- a/sc/source/core/data/documen6.cxx
+++ b/sc/source/core/data/documen6.cxx
@@ -194,7 +194,7 @@ sal_uInt8 ScDocument::GetRangeScriptType(
 
 sal_uInt8 ScDocument::GetRangeScriptType( const ScRangeList& rRanges )
 {
-    sc::ColumnSpanSet aSet;
+    sc::ColumnSpanSet aSet(false);
     for (size_t i = 0, n = rRanges.size(); i < n; ++i)
     {
         const ScRange& rRange = *rRanges[i];
@@ -206,7 +206,7 @@ sal_uInt8 ScDocument::GetRangeScriptType( const ScRangeList& rRanges )
     }
 
     ScriptTypeAggregator aAction(*this);
-    aSet.executeFromTop(aAction);
+    aSet.executeAction(aAction);
     return aAction.getScriptType();
 }
 
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 9d3c72f..2920d99 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -3538,8 +3538,7 @@ void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell )
 void ScDocument::CalcAll()
 {
     ClearLookupCaches();    // Ensure we don't deliver zombie data.
-    bool bOldAutoCalc = GetAutoCalc();
-    SetAutoCalc( true );
+    sc::AutoCalcSwitch aSwitch(*this, true);
     TableContainer::iterator it = maTabs.begin();
     for (; it != maTabs.end(); ++it)
         if (*it)
@@ -3548,7 +3547,6 @@ void ScDocument::CalcAll()
         if (*it)
             (*it)->CalcAll();
     ClearFormulaTree();
-    SetAutoCalc( bOldAutoCalc );
 }
 
 
@@ -5925,6 +5923,19 @@ void ScDocument::SetSubTotalCellsDirty(const ScRange& rDirtyRange)
     maSubTotalCells.swap(aNewSet); // update the list.
 }
 
+void ScDocument::MarkSubTotalCells( sc::ColumnSpanSet& rSet, const ScRange& rRange, bool bVal ) const
+{
+    for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
+    {
+        const ScTable* pTab = FetchTable(nTab);
+        if (!pTab)
+            continue;
+
+        pTab->MarkSubTotalCells(
+            rSet, rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), bVal);
+    }
+}
+
 sal_uInt16 ScDocument::GetTextWidth( const ScAddress& rPos ) const
 {
     SCTAB nTab = rPos.Tab();
diff --git a/sc/source/core/data/listenercontext.cxx b/sc/source/core/data/listenercontext.cxx
index 6f67920..dc92346 100644
--- a/sc/source/core/data/listenercontext.cxx
+++ b/sc/source/core/data/listenercontext.cxx
@@ -53,7 +53,7 @@ ColumnBlockPosition* StartListeningContext::getBlockPosition(SCTAB nTab, SCCOL n
 }
 
 EndListeningContext::EndListeningContext(ScDocument& rDoc) :
-    mrDoc(rDoc), mpPosSet(new ColumnBlockPositionSet(rDoc)) {}
+    mrDoc(rDoc), maSet(false), mpPosSet(new ColumnBlockPositionSet(rDoc)) {}
 
 ScDocument& EndListeningContext::getDoc()
 {
@@ -73,7 +73,7 @@ void EndListeningContext::addEmptyBroadcasterPosition(SCTAB nTab, SCCOL nCol, SC
 void EndListeningContext::purgeEmptyBroadcasters()
 {
     PurgeAction aAction(mrDoc);
-    maSet.executeFromTop(aAction);
+    maSet.executeAction(aAction);
 }
 
 }
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 03a0ca0..2cdb5df 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -55,6 +55,7 @@
 #include "cellvalue.hxx"
 #include "tokenarray.hxx"
 #include "mtvcellfunc.hxx"
+#include "columnspanset.hxx"
 
 #include <vector>
 #include <boost/unordered_set.hpp>
@@ -1159,6 +1160,36 @@ bool ScTable::DoSubTotals( ScSubTotalParam& rParam )
     return bSpaceLeft;
 }
 
+void ScTable::MarkSubTotalCells(
+    sc::ColumnSpanSet& rSet, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bVal ) const
+{
+    if (!ValidCol(nCol1) || !ValidCol(nCol2))
+        return;
+
+    // Pick up all subtotal formula cells.
+    for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+        aCol[nCol].MarkSubTotalCells(rSet, nRow1, nRow2, bVal);
+
+    // Pick up all filtered rows.
+    ScFlatBoolRowSegments::RangeData aFilteredSpan;
+    SCROW nRow = nRow1;
+    while (nRow <= nRow2)
+    {
+        if (!mpFilteredRows->getRangeData(nRow, aFilteredSpan))
+            // Failed for whatever reason.
+            return;
+
+        if (aFilteredSpan.mbValue)
+        {
+            // Filtered span found.
+            for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+                rSet.set(nTab, nCol, nRow, aFilteredSpan.mnRow2, bVal);
+        }
+
+        nRow = aFilteredSpan.mnRow2 + 1;
+    }
+}
+
 namespace {
 
 class QueryEvaluator
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 9cb89ae..f8acd73 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -58,6 +58,8 @@
 #include "queryparam.hxx"
 #include "queryentry.hxx"
 #include "tokenarray.hxx"
+#include "columnspanset.hxx"
+#include "column.hxx"
 
 #include <comphelper/processfactory.hxx>
 #include <comphelper/string.hxx>
@@ -4274,11 +4276,188 @@ void ScInterpreter::ScAverage( bool bTextAsZero )
     PushDouble( IterateParameters( ifAVERAGE, bTextAsZero ) );
 }
 
+namespace {
+
+class FuncCount : public sc::ColumnSpanSet::ColumnAction
+{
+    sc::ColumnBlockConstPosition maPos;
+    ScColumn* mpCol;
+    size_t mnCount;
+    sal_uInt32 mnNumFmt;
+
+public:
+    FuncCount() : mnCount(0), mnNumFmt(0) {}
+
+    virtual void startColumn(ScColumn* pCol)
+    {
+        mpCol = pCol;
+        mpCol->InitBlockPosition(maPos);
+    }
+
+    virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal)
+    {
+        if (!bVal)
+            return;
+
+        mnCount += mpCol->CountNumericCells(maPos, nRow1, nRow2);
+        mnNumFmt = mpCol->GetNumberFormat(nRow2);
+    };
+
+    size_t getCount() const { return mnCount; }
+    sal_uInt32 getNumberFormat() const { return mnNumFmt; }
+};
+
+}
 
 void ScInterpreter::ScCount()
 {
-    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCount" );
-    PushDouble( IterateParameters( ifCOUNT ) );
+    short nParamCount = GetByte();
+    double fVal = 0.0;
+    sal_uLong nCount = 0;
+    ScAddress aAdr;
+    ScRange aRange;
+    size_t nRefInList = 0;
+    if (nGlobalError)
+        nGlobalError = 0;
+
+    while (nParamCount-- > 0)
+    {
+        switch (GetStackType())
+        {
+            case svString:
+            {
+                String aStr( PopString() );
+                sal_uInt32 nFIndex = 0;                 // damit default Land/Spr.
+                if (pFormatter->IsNumberFormat(aStr, nFIndex, fVal))
+                    nCount++;
+            }
+            break;
+            case svDouble    :
+                nCount++;
+                nFuncFmtType = NUMBERFORMAT_NUMBER;
+                break;
+            case svExternalSingleRef:
+            {
+                ScExternalRefCache::TokenRef pToken;
+                ScExternalRefCache::CellFormat aFmt;
+                PopExternalSingleRef(pToken, &aFmt);
+                if (nGlobalError)
+                {
+                    nGlobalError = 0;
+                    break;
+                }
+
+                if (!pToken)
+                    break;
+
+                StackVar eType = pToken->GetType();
+                if (eType == formula::svDouble)
+                {
+                    nCount++;
+                    if (aFmt.mbIsSet)
+                    {
+                        nFuncFmtType = aFmt.mnType;
+                        nFuncFmtIndex = aFmt.mnIndex;
+                    }
+
+                    if (nGlobalError)
+                    {
+                        nGlobalError = 0;
+                        nCount--;
+                    }
+                }
+            }
+            break;
+            case svSingleRef :
+            {
+                PopSingleRef( aAdr );
+                if (nGlobalError)
+                {
+                    nGlobalError = 0;
+                    break;
+                }
+                if (glSubTotal && pDok->RowFiltered( aAdr.Row(), aAdr.Tab()))
+                {
+                    break;
+                }
+                ScRefCellValue aCell;
+                aCell.assign(*pDok, aAdr);
+                if (!aCell.isEmpty())
+                {
+                    if (aCell.hasNumeric())
+                    {
+                        nCount++;
+                        CurFmtToFuncFmt();
+                        if (nGlobalError)
+                        {
+                            nGlobalError = 0;
+                            nCount--;
+                        }
+                    }
+                }
+            }
+            break;
+            case svDoubleRef :
+            case svRefList :
+            {
+                PopDoubleRef( aRange, nParamCount, nRefInList);
+                if (nGlobalError)
+                {
+                    nGlobalError = 0;
+                    break;
+                }
+
+                sc::ColumnSpanSet aSet(false);
+                aSet.set(aRange, true);
+                if (glSubTotal)
+                    // Skip all filtered rows and subtotal formula cells.
+                    pDok->MarkSubTotalCells(aSet, aRange, false);
+
+                FuncCount aAction;
+                aSet.executeColumnAction(*pDok, aAction);
+                nCount = aAction.getCount();
+
+                // Get the number format of the last iterated cell.
+                nFuncFmtIndex = aAction.getNumberFormat();
+                nFuncFmtType = pDok->GetFormatTable()->GetType(nFuncFmtIndex);
+            }
+            break;
+            case svExternalDoubleRef:
+            {
+                ScMatrixRef pMat;
+                PopExternalDoubleRef(pMat);
+                if (nGlobalError)
+                    break;
+
+                double fMem = 0.0, fRes = 0.0;
+                bool bNull = true;
+                IterateMatrix(pMat, ifCOUNT, false, nCount, nFuncFmtType, fRes, fMem, bNull);
+            }
+            break;
+            case svMatrix :
+            {
+                ScMatrixRef pMat = PopMatrix();
+                double fMem = 0.0, fRes = 0.0;
+                bool bNull = true;
+                IterateMatrix(pMat, ifCOUNT, false, nCount, nFuncFmtType, fRes, fMem, bNull);
+            }
+            break;
+            case svError:
+            {
+                PopError();
+                nGlobalError = 0;
+            }
+            break;
+            default :
+                while (nParamCount-- > 0)
+                    PopError();
+                SetError(errIllegalParameter);
+        }
+    }
+
+    nFuncFmtType = NUMBERFORMAT_NUMBER;
+
+    PushDouble(nCount);
 }
 
 
commit fa0caba4c9f0cc48f59448f8b39a6629157f20e7
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jul 1 21:08:37 2013 -0400

    Nobody uses this. I forgot to remove it.
    
    Change-Id: Ib035466e04f37ee1d7b61d352f7a380f005b3231

diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx
index 79a038d..26c2378 100644
--- a/sc/source/core/tool/interpr5.cxx
+++ b/sc/source/core/tool/interpr5.cxx
@@ -1597,30 +1597,6 @@ void ScInterpreter::ScPow()
 
 namespace {
 
-bool mergeArray( std::vector<double>& rRes, const std::vector<double>& rOther )
-{
-    if (rRes.size() != rOther.size())
-        return false;
-
-    double fNan;
-    rtl::math::setNan(&fNan);
-
-    std::vector<double>::iterator it = rRes.begin(), itEnd = rRes.end();
-    std::vector<double>::const_iterator itOther = rOther.begin();
-    for (; it != itEnd; ++it, ++itOther)
-    {
-        if (rtl::math::isNan(*it) || rtl::math::isNan(*itOther))
-        {
-            *it = fNan;
-            continue;
-        }
-
-        *it *= *itOther;
-    }
-
-    return true;
-}
-
 class SumValues : std::unary_function<double, void>
 {
     double mfSum;


More information about the Libreoffice-commits mailing list