summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2018-12-13 19:26:22 +0100
committerEike Rathke <erack@redhat.com>2018-12-14 00:05:10 +0100
commitd9aaa26a4efbe7c69254ecc5f00b997f237686e9 (patch)
tree549fa984a4006d6d083cd3a12a2fbde873b64016
parent4786a09e7c41c5dc21732b2e0c74c2984c40c9b5 (diff)
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@redhat.com>
-rw-r--r--sc/inc/column.hxx2
-rw-r--r--sc/inc/subtotal.hxx52
-rw-r--r--sc/inc/table.hxx2
-rw-r--r--sc/source/core/data/column2.cxx12
-rw-r--r--sc/source/core/data/documen4.cxx6
-rw-r--r--sc/source/core/data/table3.cxx2
-rw-r--r--sc/source/core/tool/subtotal.cxx90
7 files changed, 89 insertions, 77 deletions
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: */