[Libreoffice-commits] core.git: sc/inc sc/source

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Thu Dec 13 23:05:35 UTC 2018


 sc/inc/column.hxx                |    2 
 sc/inc/subtotal.hxx              |   52 +++++++++++++---------
 sc/inc/table.hxx                 |    2 
 sc/source/core/data/column2.cxx  |   12 ++---
 sc/source/core/data/documen4.cxx |    6 +-
 sc/source/core/data/table3.cxx   |    2 
 sc/source/core/tool/subtotal.cxx |   90 +++++++++++++++++++--------------------
 7 files changed, 89 insertions(+), 77 deletions(-)

New commits:
commit d9aaa26a4efbe7c69254ecc5f00b997f237686e9
Author:     Eike Rathke <erack at redhat.com>
AuthorDate: Thu Dec 13 19:26:22 2018 +0100
Commit:     Eike Rathke <erack at redhat.com>
CommitDate: Fri Dec 14 00:05:10 2018 +0100

    Encapsulate ScFunctionData members and abuse WelfordRunner members
    
    ... to squeeze some memory and later use this as a mass object
    during consolidation.
    
    Change-Id: I3f0aa03ec0bbbb4c64a4854b55a451dd3cacfa90
    Reviewed-on: https://gerrit.libreoffice.org/65124
    Tested-by: Jenkins
    Reviewed-by: Eike Rathke <erack at redhat.com>

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index b1e890a6347c..7e12cf4eda46 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -85,7 +85,7 @@ class ScStyleSheet;
 class SvtBroadcaster;
 class ScTypedStrData;
 class ScProgress;
-struct ScFunctionData;
+class ScFunctionData;
 class ScFlatBoolRowSegments;
 struct ScSetStringParam;
 struct ScColWidthParam;
diff --git a/sc/inc/subtotal.hxx b/sc/inc/subtotal.hxx
index 2c1db3ca2264..2e2811e54815 100644
--- a/sc/inc/subtotal.hxx
+++ b/sc/inc/subtotal.hxx
@@ -30,6 +30,8 @@ public:
     static bool SafeDiv( double& fVal1, double fVal2);
 };
 
+class ScFunctionData;
+
 /** Implements the Welford Online one-pass algorithm.
     See https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_Online_algorithm
     and Donald E. Knuth, TAoCP vol.2, 3rd edn., p. 232
@@ -37,34 +39,44 @@ public:
 class WelfordRunner
 {
 public:
-    WelfordRunner() : fMean(0.0), fM2(0.0), nCount(0) {}
+    WelfordRunner() : mfMean(0.0), mfM2(0.0), mnCount(0) {}
     void        update( double fVal );
-    sal_uInt64  getCount() const                { return nCount; }
-    double      getMean() const                 { return fMean; }
-    double      getVarianceSample() const       { return nCount > 1 ? fM2 / (nCount-1) : 0.0; }
-    double      getVariancePopulation() const   { return nCount > 0 ? fM2 / nCount : 0.0; }
+    sal_uInt64  getCount() const                { return mnCount; }
+    double      getMean() const                 { return mfMean; }
+    double      getVarianceSample() const       { return mnCount > 1 ? mfM2 / (mnCount-1) : 0.0; }
+    double      getVariancePopulation() const   { return mnCount > 0 ? mfM2 / mnCount : 0.0; }
 
+    // The private variables can be abused by ScFunctionData as general
+    // sum/min/max/ave/count/... variables to reduce memory footprint for that
+    // ScFunctionData may be a mass object during consolidation.
+    // ScFunctionData::update() and getResult() take care that purposes are not
+    // mixed.
+    friend class ScFunctionData;
 private:
-    double      fMean;
-    double      fM2;
-    sal_uInt64  nCount;
+    double      mfMean;
+    double      mfM2;
+    sal_uInt64  mnCount;
 };
 
-struct ScFunctionData                   // to calculate single functions
+/** To calculate a single subtotal function. */
+class ScFunctionData
 {
-private:
-    WelfordRunner   maWelford;
-    double          nVal;
-    sal_uInt64      nCount;
 public:
-    ScSubTotalFunc const  eFunc;
-    bool            bError;
+    ScFunctionData( ScSubTotalFunc eFn ) : meFunc(eFn), mbError(false) {}
+    void             update( double fNewVal );
+    /// Check getError() after (!) obtaining the result.
+    double           getResult();
+    bool             getError() const    { return mbError; }
+    ScSubTotalFunc   getFunc() const     { return meFunc; }
+    void             setError()          { mbError = true; }
+
+private:
+    WelfordRunner           maWelford;
+    ScSubTotalFunc const    meFunc;
+    bool                    mbError;
 
-    ScFunctionData( ScSubTotalFunc eFn ) :
-        nVal(0.0), nCount(0), eFunc(eFn), bError(false) {}
-    void update( double fNewVal );
-    /// Check bError after (!) obtaining the result.
-    double getResult();
+    double&          getValueRef()  { return maWelford.mfMean; }
+    sal_uInt64&      getCountRef()  { return maWelford.mnCount; }
 };
 
 #endif
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 64bf2bd95b2c..e26ae0ae7a40 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -99,7 +99,7 @@ class ScStyleSheet;
 class ScTableProtection;
 class ScUserListData;
 struct RowInfo;
-struct ScFunctionData;
+class ScFunctionData;
 class CollatorWrapper;
 class ScFlatUInt16RowSegments;
 class ScFlatBoolRowSegments;
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 3aabfec3f611..f9b4569d5c4e 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -3378,10 +3378,10 @@ class UpdateSubTotalHandler
 
     void update(double fVal, bool bVal)
     {
-        if (mrData.bError)
+        if (mrData.getError())
             return;
 
-        switch (mrData.eFunc)
+        switch (mrData.getFunc())
         {
             case SUBTOTAL_FUNC_CNT2:    // everything
                 mrData.update( fVal);
@@ -3414,13 +3414,13 @@ public:
     {
         double fVal = 0.0;
         bool bVal = false;
-        if (mrData.eFunc != SUBTOTAL_FUNC_CNT2) // it doesn't interest us
+        if (mrData.getFunc() != SUBTOTAL_FUNC_CNT2) // it doesn't interest us
         {
 
             if (pCell->GetErrCode() != FormulaError::NONE)
             {
-                if (mrData.eFunc != SUBTOTAL_FUNC_CNT) // simply remove from count
-                    mrData.bError = true;
+                if (mrData.getFunc() != SUBTOTAL_FUNC_CNT) // simply remove from count
+                    mrData.setError();
             }
             else if (pCell->IsValue())
             {
@@ -3466,7 +3466,7 @@ void ScColumn::UpdateSelectionFunction(
 
     sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
 
-    switch (rData.eFunc)
+    switch (rData.getFunc())
     {
         case SUBTOTAL_FUNC_SELECTION_COUNT:
         {
diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx
index 040f5e6b5dc0..f02e43f0bffc 100644
--- a/sc/source/core/data/documen4.cxx
+++ b/sc/source/core/data/documen4.cxx
@@ -610,15 +610,15 @@ bool ScDocument::GetSelectionFunction( ScSubTotalFunc eFunc,
     SCTAB nMax = static_cast<SCTAB>(maTabs.size());
     ScMarkData::const_iterator itr = aMark.begin(), itrEnd = aMark.end();
 
-    for (; itr != itrEnd && *itr < nMax && !aData.bError; ++itr)
+    for (; itr != itrEnd && *itr < nMax && !aData.getError(); ++itr)
         if (maTabs[*itr])
             maTabs[*itr]->UpdateSelectionFunction(aData, aMark);
 
     rResult = aData.getResult();
-    if (aData.bError)
+    if (aData.getError())
         rResult = 0.0;
 
-    return !aData.bError;
+    return !aData.getError();
 }
 
 double ScDocument::RoundValueAsShown( double fVal, sal_uInt32 nFormat, const ScInterpreterContext* pContext ) const
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 7ffd5dfec926..5a2550ce0ead 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -3595,7 +3595,7 @@ void ScTable::UpdateSelectionFunction( ScFunctionData& rData, const ScMarkData&
     }
     const SCCOL nStartCol = aMarkArea.aStart.Col();
     const SCCOL nEndCol = aMarkArea.aEnd.Col();
-    for (SCCOL nCol = nStartCol; nCol <= nEndCol && !rData.bError; ++nCol)
+    for (SCCOL nCol = nStartCol; nCol <= nEndCol && !rData.getError(); ++nCol)
     {
         if (mpColFlags && ColHidden(nCol))
             continue;
diff --git a/sc/source/core/tool/subtotal.cxx b/sc/source/core/tool/subtotal.cxx
index 44bec5477756..8fdb2d2342fb 100644
--- a/sc/source/core/tool/subtotal.cxx
+++ b/sc/source/core/tool/subtotal.cxx
@@ -64,54 +64,54 @@ bool SubTotal::SafeDiv(double& fVal1, double fVal2)
 
 void ScFunctionData::update( double fNewVal )
 {
-    if (bError)
+    if (mbError)
         return;
 
-    switch (eFunc)
+    switch (meFunc)
     {
         case SUBTOTAL_FUNC_SUM:
-            if (!SubTotal::SafePlus(nVal, fNewVal))
-                bError = true;
+            if (!SubTotal::SafePlus(getValueRef(), fNewVal))
+                mbError = true;
         break;
         case SUBTOTAL_FUNC_PROD:
-            if (nCount == 0)    // copy first value (nVal is initialized to 0)
+            if (getCountRef() == 0)    // copy first value (nVal is initialized to 0)
             {
-                nVal = fNewVal;
-                nCount = 1;     // don't care about further count
+                getValueRef() = fNewVal;
+                getCountRef() = 1;     // don't care about further count
             }
-            else if (!SubTotal::SafeMult(nVal, fNewVal))
-                bError = true;
+            else if (!SubTotal::SafeMult(getValueRef(), fNewVal))
+                mbError = true;
         break;
         case SUBTOTAL_FUNC_CNT:
         case SUBTOTAL_FUNC_CNT2:
-            ++nCount;
+            ++getCountRef();
         break;
         case SUBTOTAL_FUNC_SELECTION_COUNT:
-            nCount += fNewVal;
+            getCountRef() += fNewVal;
         break;
         case SUBTOTAL_FUNC_AVE:
-            if (!SubTotal::SafePlus(nVal, fNewVal))
-                bError = true;
+            if (!SubTotal::SafePlus(getValueRef(), fNewVal))
+                mbError = true;
             else
-                ++nCount;
+                ++getCountRef();
         break;
         case SUBTOTAL_FUNC_MAX:
-            if (nCount == 0)    // copy first value (nVal is initialized to 0)
+            if (getCountRef() == 0)    // copy first value (nVal is initialized to 0)
             {
-                nVal = fNewVal;
-                nCount = 1;     // don't care about further count
+                getValueRef() = fNewVal;
+                getCountRef() = 1;     // don't care about further count
             }
-            else if (fNewVal > nVal)
-                nVal = fNewVal;
+            else if (fNewVal > getValueRef())
+                getValueRef() = fNewVal;
         break;
         case SUBTOTAL_FUNC_MIN:
-            if (nCount == 0)    // copy first value (nVal is initialized to 0)
+            if (getCountRef() == 0)    // copy first value (nVal is initialized to 0)
             {
-                nVal = fNewVal;
-                nCount = 1;     // don't care about further count
+                getValueRef() = fNewVal;
+                getCountRef() = 1;     // don't care about further count
             }
-            else if (fNewVal < nVal)
-                nVal = fNewVal;
+            else if (fNewVal < getValueRef())
+                getValueRef() = fNewVal;
         break;
         case SUBTOTAL_FUNC_VAR:
         case SUBTOTAL_FUNC_STD:
@@ -121,83 +121,83 @@ void ScFunctionData::update( double fNewVal )
         break;
         default:
             // unhandled unknown
-            bError = true;
+            mbError = true;
     }
 }
 
 double ScFunctionData::getResult()
 {
-    if (bError)
+    if (mbError)
         return 0.0;
 
     double fRet = 0.0;
-    switch (eFunc)
+    switch (meFunc)
     {
         case SUBTOTAL_FUNC_CNT:
         case SUBTOTAL_FUNC_CNT2:
         case SUBTOTAL_FUNC_SELECTION_COUNT:
-            fRet = nCount;
+            fRet = getCountRef();
         break;
         case SUBTOTAL_FUNC_SUM:
         case SUBTOTAL_FUNC_MAX:
         case SUBTOTAL_FUNC_MIN:
             // Note that nVal is 0.0 for MAX and MIN if nCount==0, that's also
             // how it is defined in ODFF.
-            fRet = nVal;
+            fRet = getValueRef();
         break;
         case SUBTOTAL_FUNC_PROD:
-            fRet = (nCount > 0) ? nVal : 0.0;
+            fRet = (getCountRef() > 0) ? getValueRef() : 0.0;
         break;
         case SUBTOTAL_FUNC_AVE:
-            if (nCount == 0)
-                bError = true;
+            if (getCountRef() == 0)
+                mbError = true;
             else
-                fRet = nVal / nCount;
+                fRet = getValueRef() / getCountRef();
         break;
         case SUBTOTAL_FUNC_VAR:
         case SUBTOTAL_FUNC_STD:
             if (maWelford.getCount() < 2)
-                bError = true;
+                mbError = true;
             else
             {
                 fRet = maWelford.getVarianceSample();
                 if (fRet < 0.0)
-                    bError = true;
-                else if (eFunc == SUBTOTAL_FUNC_STD)
+                    mbError = true;
+                else if (meFunc == SUBTOTAL_FUNC_STD)
                     fRet = sqrt( fRet);
             }
         break;
         case SUBTOTAL_FUNC_VARP:
         case SUBTOTAL_FUNC_STDP:
             if (maWelford.getCount() < 1)
-                bError = true;
+                mbError = true;
             else if (maWelford.getCount() == 1)
                 fRet = 0.0;
             else
             {
                 fRet = maWelford.getVariancePopulation();
                 if (fRet < 0.0)
-                    bError = true;
-                else if (eFunc == SUBTOTAL_FUNC_STDP)
+                    mbError = true;
+                else if (meFunc == SUBTOTAL_FUNC_STDP)
                     fRet = sqrt( fRet);
             }
         break;
         default:
             assert(!"unhandled unknown");
-            bError = true;
+            mbError = true;
         break;
     }
-    if (bError)
+    if (mbError)
         fRet = 0.0;
     return fRet;
 }
 
 void WelfordRunner::update( double fVal )
 {
-    ++nCount;
-    const double fDelta = fVal - fMean;
-    fMean += fDelta / nCount;
-    fM2 += fDelta * (fVal - fMean);
+    ++mnCount;
+    const double fDelta = fVal - mfMean;
+    mfMean += fDelta / mnCount;
+    mfM2 += fDelta * (fVal - mfMean);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list