[Libreoffice-commits] core.git: 7 commits - sc/inc sc/source
Michael Meeks
michael.meeks at suse.com
Tue Jul 2 20:17:23 PDT 2013
sc/inc/column.hxx | 3
sc/inc/formulacell.hxx | 11
sc/inc/formulagroup.hxx | 5
sc/inc/types.hxx | 7
sc/source/core/data/column.cxx | 74 ---
sc/source/core/data/column2.cxx | 20
sc/source/core/data/formulacell.cxx | 40 +
sc/source/core/tool/formulagroup.cxx | 72 ++-
sc/source/core/tool/interpr1.cxx | 767 --------------------------------
sc/source/core/tool/interpr6.cxx | 836 ++++++++++++++++++++++++++++++++++-
10 files changed, 965 insertions(+), 870 deletions(-)
New commits:
commit b81d130626c20b806fc8a28524b38756eebc6c46
Author: Michael Meeks <michael.meeks at suse.com>
Date: Tue Jul 2 22:01:01 2013 +0100
Dummy formula group interpreter for testing.
diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
index 1c573c4..e645968 100644
--- a/sc/inc/formulagroup.hxx
+++ b/sc/inc/formulagroup.hxx
@@ -30,9 +30,8 @@ struct FormulaGroupContext : boost::noncopyable
};
/**
- * All the vectorized formula calculation code should be collected here.
- *
- * Abstract base class for formula group interpreters, and a factory.
+ * Abstract base class for vectorised formula group interpreters,
+ * plus a global instance factory.
*/
class SC_DLLPUBLIC FormulaGroupInterpreter
{
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index b20b437..b4fd646 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -20,6 +20,8 @@
#include <vector>
+#define USE_DUMMY_INTERPRETER 1
+
namespace sc {
ScMatrixRef FormulaGroupInterpreterSoftware::inverseMatrix(const ScMatrix& /*rMat*/)
@@ -108,14 +110,61 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
namespace opencl {
extern sc::FormulaGroupInterpreter *createFormulaGroupInterpreter();
}
-
FormulaGroupInterpreter *FormulaGroupInterpreter::msInstance = NULL;
+#if USE_DUMMY_INTERPRETER
+class FormulaGroupInterpreterDummy : public FormulaGroupInterpreter
+{
+ enum Mode {
+ WRITE_OUTPUT = 0
+ };
+ Mode meMode;
+public:
+ FormulaGroupInterpreterDummy()
+ {
+ const char *pValue = getenv("FORMULA_GROUP_DUMMY");
+ meMode = static_cast<Mode>(OString(pValue, strlen(pValue)).toInt32());
+ fprintf(stderr, "Using Dummy Formula Group interpreter mode %d\n", (int)meMode);
+ }
+
+ virtual ScMatrixRef inverseMatrix(const ScMatrix& /*rMat*/)
+ {
+ return ScMatrixRef();
+ }
+
+ virtual bool interpret(ScDocument& rDoc, const ScAddress& rTopPos,
+ const ScFormulaCellGroupRef& xGroup,
+ ScTokenArray& rCode)
+ {
+ (void)rCode;
+
+ // Write simple data back into the sheet
+ if (meMode == WRITE_OUTPUT)
+ {
+ double *pDoubles = new double[xGroup->mnLength];
+ for (sal_Int32 i = 0; i < xGroup->mnLength; i++)
+ pDoubles[i] = 42.0 + i;
+ rDoc.SetFormulaResults(rTopPos, pDoubles, xGroup->mnLength);
+ delete [] pDoubles;
+ }
+ return true;
+ }
+};
+#endif
+
/// load and/or configure the correct formula group interpreter
FormulaGroupInterpreter *FormulaGroupInterpreter::getStatic()
{
static bool bOpenCLEnabled = false;
+#if USE_DUMMY_INTERPRETER
+ if (getenv("FORMULA_GROUP_DUMMY"))
+ {
+ delete msInstance;
+ return msInstance = new sc::FormulaGroupInterpreterDummy();
+ }
+#endif
+
if ( msInstance &&
bOpenCLEnabled != ScInterpreter::GetGlobalConfig().mbOpenCLEnabled )
{
commit 1eb0aac39f366caf497534de00fb30b84ac1ba62
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date: Tue Jul 2 22:23:56 2013 -0400
Forgot to remove these debug statements.
Change-Id: I680750c43dce4b6e7f9b9ed0a6b8550bdf485a8c
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 132ed5c..f8928e5 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3115,12 +3115,8 @@ bool ScFormulaCell::InterpretFormulaGroup()
if (!xGroup || !pCode)
return false;
- fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: calc state = %d\n", xGroup->meCalcState);
if (xGroup->meCalcState == sc::GroupCalcDisabled)
- {
- fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: group calc disabled.\n");
return false;
- }
switch (pCode->GetVectorState())
{
@@ -3145,7 +3141,6 @@ bool ScFormulaCell::InterpretFormulaGroup()
GroupTokenConverter aConverter(aCxt, aCode, *pDocument, *this, aTopPos);
if (!aConverter.convert(*pCode))
{
- fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: disabling group calc due to failed conversion\n");
xGroup->meCalcState = sc::GroupCalcDisabled;
return false;
}
@@ -3153,7 +3148,6 @@ bool ScFormulaCell::InterpretFormulaGroup()
xGroup->meCalcState = sc::GroupCalcRunning;
if (!sc::FormulaGroupInterpreter::getStatic()->interpret(*pDocument, aTopPos, xGroup, aCode))
{
- fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: disabling group calc due to failed calculation\n");
xGroup->meCalcState = sc::GroupCalcDisabled;
return false;
}
commit ce7a2d39efc66ae682873a96030332b38ba3a4d6
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date: Tue Jul 2 22:10:25 2013 -0400
Detect circular dependency in formula groups to fallback to cell-based.
Change-Id: Icfb4fd4be4e0c1f6f450fb8ddce57c7b79568e6f
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 52a1474..07b726a 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -24,6 +24,7 @@
#include "formula/tokenarray.hxx"
#include "svl/listener.hxx"
+#include "types.hxx"
#include <set>
@@ -40,19 +41,23 @@ struct ScSimilarFormulaDelta;
struct SC_DLLPUBLIC ScFormulaCellGroup
{
- sal_Int32 mnRefCount;
+ mutable size_t mnRefCount;
+
SCROW mnStart; // Start offset of that cell
SCROW mnLength; // How many of these do we have ?
bool mbInvariant;
+ sc::GroupCalcState meCalcState;
ScFormulaCellGroup();
~ScFormulaCellGroup();
};
-inline void intrusive_ptr_add_ref(ScFormulaCellGroup *p)
+
+inline void intrusive_ptr_add_ref(const ScFormulaCellGroup *p)
{
p->mnRefCount++;
}
-inline void intrusive_ptr_release(ScFormulaCellGroup *p)
+
+inline void intrusive_ptr_release(const ScFormulaCellGroup *p)
{
if( --p->mnRefCount == 0 )
delete p;
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 445311e..5c11da5 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -56,6 +56,13 @@ const sal_uInt16 MatrixEdgeTop = 8;
const sal_uInt16 MatrixEdgeRight = 16;
const sal_uInt16 MatrixEdgeOpen = 32;
+enum GroupCalcState
+{
+ GroupCalcEnabled,
+ GroupCalcRunning,
+ GroupCalcDisabled
+};
+
}
#endif
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 4becbb7..82daadf 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2166,10 +2166,15 @@ bool appendDouble(
nLenRemain = 0;
}
+ sal_uInt16 nErr;
+ double fVal;
for (; itData != itDataEnd; ++itData)
{
ScFormulaCell& rFC = **itData;
- rArray.push_back(rFC.GetValue());
+ if (!rFC.GetErrorOrValue(nErr, fVal) || nErr)
+ return false;
+
+ rArray.push_back(fVal);
}
}
break;
@@ -2238,6 +2243,9 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
break;
case sc::element_type_formula:
{
+ sal_uInt16 nErr;
+ double fVal;
+
rCxt.maArrays.push_back(new sc::FormulaGroupContext::DoubleArrayType);
sc::FormulaGroupContext::DoubleArrayType& rArray = rCxt.maArrays.back();
rArray.reserve(nLenRequested);
@@ -2252,7 +2260,10 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
for (; it != itEnd; ++it)
{
ScFormulaCell& rCell = **it;
- rArray.push_back(rCell.GetValue()); // the cell may be interpreted.
+ if (!rCell.GetErrorOrValue(nErr, fVal) || nErr)
+ return NULL;
+
+ rArray.push_back(fVal);
}
return &rArray[0];
@@ -2264,7 +2275,10 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
for (; it != itEnd; ++it)
{
ScFormulaCell& rCell = **it;
- rArray.push_back(rCell.GetValue()); // the cell may be interpreted.
+ if (!rCell.GetErrorOrValue(nErr, fVal) || nErr)
+ return NULL;
+
+ rArray.push_back(fVal);
}
// Fill the remaining array with values from the following blocks.
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index a129726..132ed5c 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -382,7 +382,11 @@ void adjustDBRange(ScToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldD
}
ScFormulaCellGroup::ScFormulaCellGroup() :
- mnRefCount(0), mnStart(0), mnLength(0), mbInvariant(false)
+ mnRefCount(0),
+ mnStart(0),
+ mnLength(0),
+ mbInvariant(false),
+ meCalcState(sc::GroupCalcEnabled)
{
}
@@ -1547,6 +1551,9 @@ void ScFormulaCell::SetDirty( bool bDirtyFlag )
void ScFormulaCell::SetDirtyVar()
{
bDirty = true;
+ if (xGroup)
+ xGroup->meCalcState = sc::GroupCalcEnabled;
+
// mark the sheet of this cell to be calculated
//#FIXME do we need to revert this remnant of old fake vba events? pDocument->AddCalculateTable( aPos.Tab() );
}
@@ -1611,7 +1618,7 @@ void ScFormulaCell::SetErrCode( sal_uInt16 n )
void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits )
{
if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL )
- bDirty = true;
+ SetDirtyVar();
if ( nBits & RECALCMODE_ONLOAD_ONCE )
{ // OnLoadOnce nur zum Dirty setzen nach Filter-Import
nBits = (nBits & ~RECALCMODE_EMASK) | RECALCMODE_NORMAL;
@@ -2959,9 +2966,10 @@ class GroupTokenConverter
ScTokenArray& mrGroupTokens;
ScDocument& mrDoc;
ScFormulaCell& mrCell;
+ const ScAddress& mrPos;
public:
- GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell) :
- mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell) {}
+ GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) :
+ mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos) {}
bool convert(ScTokenArray& rCode)
{
@@ -2979,8 +2987,7 @@ public:
case svSingleRef:
{
ScSingleRefData aRef = pToken->GetSingleRef();
- aRef.CalcAbsIfRel(mrCell.aPos);
- ScAddress aRefPos(aRef.nCol, aRef.nRow, aRef.nTab);
+ ScAddress aRefPos = aRef.toAbs(mrPos);
if (aRef.IsRowRel())
{
// Fetch double array guarantees that the length of the
@@ -3108,6 +3115,13 @@ bool ScFormulaCell::InterpretFormulaGroup()
if (!xGroup || !pCode)
return false;
+ fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: calc state = %d\n", xGroup->meCalcState);
+ if (xGroup->meCalcState == sc::GroupCalcDisabled)
+ {
+ fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: group calc disabled.\n");
+ return false;
+ }
+
switch (pCode->GetVectorState())
{
case FormulaVectorEnabled:
@@ -3126,10 +3140,26 @@ bool ScFormulaCell::InterpretFormulaGroup()
sc::FormulaGroupContext aCxt;
ScTokenArray aCode;
- GroupTokenConverter aConverter(aCxt, aCode, *pDocument, *this);
+ ScAddress aTopPos = aPos;
+ aTopPos.SetRow(xGroup->mnStart);
+ GroupTokenConverter aConverter(aCxt, aCode, *pDocument, *this, aTopPos);
if (!aConverter.convert(*pCode))
+ {
+ fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: disabling group calc due to failed conversion\n");
+ xGroup->meCalcState = sc::GroupCalcDisabled;
+ return false;
+ }
+
+ xGroup->meCalcState = sc::GroupCalcRunning;
+ if (!sc::FormulaGroupInterpreter::getStatic()->interpret(*pDocument, aTopPos, xGroup, aCode))
+ {
+ fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: disabling group calc due to failed calculation\n");
+ xGroup->meCalcState = sc::GroupCalcDisabled;
return false;
- return sc::FormulaGroupInterpreter::getStatic()->interpret(*pDocument, aPos, xGroup, aCode);
+ }
+
+ xGroup->meCalcState = sc::GroupCalcEnabled;
+ return true;
}
bool ScFormulaCell::InterpretInvariantFormulaGroup()
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 79621ea..b20b437 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -33,18 +33,14 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
{
// Decompose the group into individual cells and calculate them individually.
- // Always set the top row to be the top of the group. Grouped formula
- // cells are to be calculated for its full segment at all times.
-
- ScAddress aTopPos = rTopPos;
- aTopPos.SetRow(xGroup->mnStart);
- ScAddress aTmpPos = aTopPos;
+ // The caller must ensure that the top position is the start position of
+ // the group.
+ ScAddress aTmpPos = rTopPos;
std::vector<double> aResults;
aResults.reserve(xGroup->mnLength);
- for (SCROW i = 0; i < xGroup->mnLength; ++i)
+ for (SCROW i = 0; i < xGroup->mnLength; ++i, aTmpPos.IncRow())
{
- aTmpPos.SetRow(aTopPos.Row() + i);
ScTokenArray aCode2;
for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
{
@@ -103,7 +99,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
} // for loop end (xGroup->mnLength)
if (!aResults.empty())
- rDoc.SetFormulaResults(aTopPos, &aResults[0], aResults.size());
+ rDoc.SetFormulaResults(rTopPos, &aResults[0], aResults.size());
return true;
}
commit 041e7dce8097fe2a4fe1cc853cab463dd5ea72e5
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date: Tue Jul 2 18:55:29 2013 -0400
Actually we need to reset the top row to be the top of the group.
To ensure that a group of formula cells are either all clean or all
dirty at any given time. We'll fallback to non-grouped calculation
mode if that's not possible.
Change-Id: I8a5d4740571ca149d32a4630555e3c213c222ef3
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 3dd43e3..79621ea 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -33,14 +33,18 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
{
// Decompose the group into individual cells and calculate them individually.
- ScAddress aTmpPos = rTopPos;
- SCROW nOffset = rTopPos.Row() - xGroup->mnStart;
- SCROW nLength = xGroup->mnLength - nOffset;
+ // Always set the top row to be the top of the group. Grouped formula
+ // cells are to be calculated for its full segment at all times.
+
+ ScAddress aTopPos = rTopPos;
+ aTopPos.SetRow(xGroup->mnStart);
+ ScAddress aTmpPos = aTopPos;
+
std::vector<double> aResults;
- aResults.reserve(nLength);
- for (SCROW i = 0; i < nLength; ++i)
+ aResults.reserve(xGroup->mnLength);
+ for (SCROW i = 0; i < xGroup->mnLength; ++i)
{
- aTmpPos.SetRow(rTopPos.Row() + i);
+ aTmpPos.SetRow(aTopPos.Row() + i);
ScTokenArray aCode2;
for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
{
@@ -99,7 +103,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
} // for loop end (xGroup->mnLength)
if (!aResults.empty())
- rDoc.SetFormulaResults(rTopPos, &aResults[0], aResults.size());
+ rDoc.SetFormulaResults(aTopPos, &aResults[0], aResults.size());
return true;
}
commit 75cfc9a332b224597872960df22091ca76747058
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date: Tue Jul 2 16:47:31 2013 -0400
Be aware that the top row may not always be the top of the group.
Adjust the length and the starting row position for accordingly.
Change-Id: I2f9c5a515887b98334bad51c5409461d5dd1505d
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 4754bd0..3dd43e3 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -18,6 +18,8 @@
#include "formula/vectortoken.hxx"
+#include <vector>
+
namespace sc {
ScMatrixRef FormulaGroupInterpreterSoftware::inverseMatrix(const ScMatrix& /*rMat*/)
@@ -29,12 +31,16 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
const ScFormulaCellGroupRef& xGroup,
ScTokenArray& rCode)
{
- // Until we implement group calculation for real, decompose the group into
- // individual formula token arrays for individual calculation.
+ // Decompose the group into individual cells and calculate them individually.
+
ScAddress aTmpPos = rTopPos;
- for (sal_Int32 i = 0; i < xGroup->mnLength; ++i)
+ SCROW nOffset = rTopPos.Row() - xGroup->mnStart;
+ SCROW nLength = xGroup->mnLength - nOffset;
+ std::vector<double> aResults;
+ aResults.reserve(nLength);
+ for (SCROW i = 0; i < nLength; ++i)
{
- aTmpPos.SetRow(xGroup->mnStart + i);
+ aTmpPos.SetRow(rTopPos.Row() + i);
ScTokenArray aCode2;
for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
{
@@ -89,11 +95,12 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
aComp.CompileTokenArray(); // Create RPN token array.
ScInterpreter aInterpreter(pDest, &rDoc, aTmpPos, aCode2);
aInterpreter.Interpret();
- pDest->SetResultToken(aInterpreter.GetResultToken().get());
- pDest->ResetDirty();
- pDest->SetChanged(true);
+ aResults.push_back(aInterpreter.GetResultToken()->GetDouble());
} // for loop end (xGroup->mnLength)
+ if (!aResults.empty())
+ rDoc.SetFormulaResults(rTopPos, &aResults[0], aResults.size());
+
return true;
}
commit d61233a388284383a939e2f26a0e25b9ad243898
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date: Tue Jul 2 16:02:59 2013 -0400
Move this code from the column code back into the interpreter code.
Change-Id: I7830cdf3f09ed7b6ae6221212bfb84abcdeac523
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 359b8ac..62e1ddf 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -409,9 +409,6 @@ public:
void ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark );
void ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark );
- double SumNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const;
- 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/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 61f57ab..6a2dbd3 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -466,80 +466,6 @@ void ScColumn::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
}
}
-namespace {
-
-class NumericCellAccumulator
-{
- double mfSum;
-public:
- NumericCellAccumulator() : mfSum(0.0) {}
-
- void operator() (size_t, double fVal)
- {
- mfSum += fVal;
- }
-
- void operator() (size_t, const ScFormulaCell* pCell)
- {
- ScFormulaCell& rCell = const_cast<ScFormulaCell&>(*pCell);
- if (rCell.IsValue())
- mfSum += rCell.GetValue();
- }
-
- double getSum() const { return mfSum; }
-};
-
-class NumericCellCounter
-{
- size_t mnCount;
-public:
- NumericCellCounter() : mnCount(0) {}
-
- void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize)
- {
- switch (rNode.type)
- {
- case sc::element_type_numeric:
- mnCount += nDataSize;
- break;
- case sc::element_type_formula:
- {
- sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
- std::advance(it, nOffset);
- sc::formula_block::const_iterator itEnd = it;
- std::advance(itEnd, nDataSize);
- for (; it != itEnd; ++it)
- {
- ScFormulaCell& rCell = const_cast<ScFormulaCell&>(**it);
- if (rCell.IsValueNoError())
- ++mnCount;
- }
- }
- break;
- default:
- ;
- }
- }
-
- size_t getCount() const { return mnCount; }
-};
-
-}
-
-double ScColumn::SumNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const
-{
- NumericCellAccumulator aFunc;
- rPos.miCellPos = sc::ParseFormulaNumeric(rPos.miCellPos, maCells, nRow1, nRow2, aFunc);
- return aFunc.getSum();
-}
-
-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 )
{
SCROW nTop;
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index e31a062..03d87a9 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -24,6 +24,7 @@
#include "document.hxx"
#include "cellvalue.hxx"
#include "dociter.hxx"
+#include "mtvcellfunc.hxx"
#include "formula/token.hxx"
#include <rtl/logfile.hxx>
@@ -213,6 +214,62 @@ double ScInterpreter::GetGammaDist( double fX, double fAlpha, double fLambda )
namespace {
+class NumericCellAccumulator
+{
+ double mfSum;
+public:
+ NumericCellAccumulator() : mfSum(0.0) {}
+
+ void operator() (size_t, double fVal)
+ {
+ mfSum += fVal;
+ }
+
+ void operator() (size_t, const ScFormulaCell* pCell)
+ {
+ ScFormulaCell& rCell = const_cast<ScFormulaCell&>(*pCell);
+ if (rCell.IsValue())
+ mfSum += rCell.GetValue();
+ }
+
+ double getSum() const { return mfSum; }
+};
+
+class NumericCellCounter
+{
+ size_t mnCount;
+public:
+ NumericCellCounter() : mnCount(0) {}
+
+ void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize)
+ {
+ switch (rNode.type)
+ {
+ case sc::element_type_numeric:
+ mnCount += nDataSize;
+ break;
+ case sc::element_type_formula:
+ {
+ sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
+ std::advance(it, nOffset);
+ sc::formula_block::const_iterator itEnd = it;
+ std::advance(itEnd, nDataSize);
+ for (; it != itEnd; ++it)
+ {
+ ScFormulaCell& rCell = const_cast<ScFormulaCell&>(**it);
+ if (rCell.IsValueNoError())
+ ++mnCount;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ }
+
+ size_t getCount() const { return mnCount; }
+};
+
class FuncCount : public sc::ColumnSpanSet::ColumnAction
{
sc::ColumnBlockConstPosition maPos;
@@ -234,7 +291,9 @@ public:
if (!bVal)
return;
- mnCount += mpCol->CountNumericCells(maPos, nRow1, nRow2);
+ NumericCellCounter aFunc;
+ maPos.miCellPos = sc::ParseBlock(maPos.miCellPos, mpCol->GetCellStore(), aFunc, nRow1, nRow2);
+ mnCount += aFunc.getCount();
mnNumFmt = mpCol->GetNumberFormat(nRow2);
};
@@ -263,7 +322,9 @@ public:
if (!bVal)
return;
- mfSum += mpCol->SumNumericCells(maPos, nRow1, nRow2);
+ NumericCellAccumulator aFunc;
+ maPos.miCellPos = sc::ParseFormulaNumeric(maPos.miCellPos, mpCol->GetCellStore(), nRow1, nRow2, aFunc);
+ mfSum += aFunc.getSum();
mnNumFmt = mpCol->GetNumberFormat(nRow2);
};
commit 4277d968eb4407e22a3d4b467340a347e43e7ea9
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date: Tue Jul 2 15:43:57 2013 -0400
Move this to another file to distribute the compiler load.
interpr1.cxx is getting way too big....
Change-Id: Ic3e4879daebd09c8dcb86a42b305864dcc1c67c4
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 93bcfef..8b738fa 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -58,8 +58,6 @@
#include "queryparam.hxx"
#include "queryentry.hxx"
#include "tokenarray.hxx"
-#include "columnspanset.hxx"
-#include "column.hxx"
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>
@@ -3852,771 +3850,6 @@ void ScInterpreter::ScMax( bool bTextAsZero )
PushDouble(nMax);
}
-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; }
-};
-
-class FuncSum : public sc::ColumnSpanSet::ColumnAction
-{
- sc::ColumnBlockConstPosition maPos;
- ScColumn* mpCol;
- double mfSum;
- sal_uInt32 mnNumFmt;
-
-public:
- FuncSum() : mfSum(0.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;
-
- mfSum += mpCol->SumNumericCells(maPos, nRow1, nRow2);
- mnNumFmt = mpCol->GetNumberFormat(nRow2);
- };
-
- double getSum() const { return mfSum; }
- sal_uInt32 getNumberFormat() const { return mnNumFmt; }
-};
-
-void IterateMatrix(
- const ScMatrixRef& pMat, ScIterFunc eFunc, bool bTextAsZero,
- sal_uLong& rCount, short& rFuncFmtType, double& fRes, double& fMem, bool& bNull)
-{
- if (!pMat)
- return;
-
- rFuncFmtType = NUMBERFORMAT_NUMBER;
- switch (eFunc)
- {
- case ifAVERAGE:
- case ifSUM:
- {
- ScMatrix::IterateResult aRes = pMat->Sum(bTextAsZero);
- if (bNull)
- {
- bNull = false;
- fMem = aRes.mfFirst;
- fRes += aRes.mfRest;
- }
- else
- fRes += aRes.mfFirst + aRes.mfRest;
- rCount += aRes.mnCount;
- }
- break;
- case ifCOUNT:
- rCount += pMat->Count(bTextAsZero);
- break;
- case ifCOUNT2:
- rCount += pMat->Count(true);
- break;
- case ifPRODUCT:
- {
- ScMatrix::IterateResult aRes = pMat->Product(bTextAsZero);
- fRes *= aRes.mfRest;
- rCount += aRes.mnCount;
- }
- break;
- case ifSUMSQ:
- {
- ScMatrix::IterateResult aRes = pMat->SumSquare(bTextAsZero);
- fRes += aRes.mfRest;
- rCount += aRes.mnCount;
- }
- break;
- default:
- ;
- }
-}
-
-}
-
-double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
-{
- RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IterateParameters" );
- short nParamCount = GetByte();
- double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
- double fVal = 0.0;
- double fMem = 0.0; // first numeric value.
- bool bNull = true;
- sal_uLong nCount = 0;
- ScAddress aAdr;
- ScRange aRange;
- size_t nRefInList = 0;
- if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
- nGlobalError = 0;
- while (nParamCount-- > 0)
- {
- switch (GetStackType())
- {
- case svString:
- {
- if( eFunc == ifCOUNT )
- {
- String aStr( PopString() );
- sal_uInt32 nFIndex = 0; // damit default Land/Spr.
- if ( bTextAsZero || pFormatter->IsNumberFormat(aStr, nFIndex, fVal))
- nCount++;
- }
- else
- {
- switch ( eFunc )
- {
- case ifAVERAGE:
- case ifSUM:
- case ifSUMSQ:
- case ifPRODUCT:
- {
- if ( bTextAsZero )
- {
- Pop();
- nCount++;
- if ( eFunc == ifPRODUCT )
- fRes = 0.0;
- }
- else
- {
- while (nParamCount-- > 0)
- Pop();
- SetError( errNoValue );
- }
- }
- break;
- default:
- Pop();
- nCount++;
- }
- }
- }
- break;
- case svDouble :
- fVal = GetDouble();
- nCount++;
- switch( eFunc )
- {
- case ifAVERAGE:
- case ifSUM:
- if ( bNull && fVal != 0.0 )
- {
- bNull = false;
- fMem = fVal;
- }
- else
- fRes += fVal;
- break;
- case ifSUMSQ: fRes += fVal * fVal; break;
- case ifPRODUCT: fRes *= fVal; break;
- default: ; // nothing
- }
- nFuncFmtType = NUMBERFORMAT_NUMBER;
- break;
- case svExternalSingleRef:
- {
- ScExternalRefCache::TokenRef pToken;
- ScExternalRefCache::CellFormat aFmt;
- PopExternalSingleRef(pToken, &aFmt);
- if (nGlobalError && (eFunc == ifCOUNT2 || eFunc == ifCOUNT))
- {
- nGlobalError = 0;
- if ( eFunc == ifCOUNT2 )
- ++nCount;
- break;
- }
-
- if (!pToken)
- break;
-
- StackVar eType = pToken->GetType();
- if (eFunc == ifCOUNT2)
- {
- if (eType != formula::svEmptyCell)
- nCount++;
- if (nGlobalError)
- nGlobalError = 0;
- }
- else if (eType == formula::svDouble)
- {
- nCount++;
- fVal = pToken->GetDouble();
- if (aFmt.mbIsSet)
- {
- nFuncFmtType = aFmt.mnType;
- nFuncFmtIndex = aFmt.mnIndex;
- }
- switch( eFunc )
- {
- case ifAVERAGE:
- case ifSUM:
- if ( bNull && fVal != 0.0 )
- {
- bNull = false;
- fMem = fVal;
- }
- else
- fRes += fVal;
- break;
- case ifSUMSQ: fRes += fVal * fVal; break;
- case ifPRODUCT: fRes *= fVal; break;
- case ifCOUNT:
- if ( nGlobalError )
- {
- nGlobalError = 0;
- nCount--;
- }
- break;
- default: ; // nothing
- }
- }
- else if (bTextAsZero && eType == formula::svString)
- {
- nCount++;
- if ( eFunc == ifPRODUCT )
- fRes = 0.0;
- }
- }
- break;
- case svSingleRef :
- {
- PopSingleRef( aAdr );
- if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
- {
- nGlobalError = 0;
- if ( eFunc == ifCOUNT2 )
- ++nCount;
- break;
- }
- if (glSubTotal && pDok->RowFiltered( aAdr.Row(), aAdr.Tab()))
- {
- break;
- }
- ScRefCellValue aCell;
- aCell.assign(*pDok, aAdr);
- if (!aCell.isEmpty())
- {
- if( eFunc == ifCOUNT2 )
- {
- CellType eCellType = aCell.meType;
- if (eCellType != CELLTYPE_NONE)
- nCount++;
- if ( nGlobalError )
- nGlobalError = 0;
- }
- else if (aCell.hasNumeric())
- {
- nCount++;
- fVal = GetCellValue(aAdr, aCell);
- CurFmtToFuncFmt();
- switch( eFunc )
- {
- case ifAVERAGE:
- case ifSUM:
- if ( bNull && fVal != 0.0 )
- {
- bNull = false;
- fMem = fVal;
- }
- else
- fRes += fVal;
- break;
- case ifSUMSQ: fRes += fVal * fVal; break;
- case ifPRODUCT: fRes *= fVal; break;
- case ifCOUNT:
- if ( nGlobalError )
- {
- nGlobalError = 0;
- nCount--;
- }
- break;
- default: ; // nothing
- }
- }
- else if (bTextAsZero && aCell.hasString())
- {
- nCount++;
- if ( eFunc == ifPRODUCT )
- fRes = 0.0;
- }
- }
- }
- break;
- case svDoubleRef :
- case svRefList :
- {
- PopDoubleRef( aRange, nParamCount, nRefInList);
- if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
- {
- nGlobalError = 0;
- if ( eFunc == ifCOUNT2 )
- ++nCount;
- break;
- }
- if( eFunc == ifCOUNT2 )
- {
- ScCellIterator aIter( pDok, aRange, glSubTotal );
- for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
- {
- if (!aIter.hasEmptyData())
- ++nCount;
- }
-
- if ( nGlobalError )
- nGlobalError = 0;
- }
- else
- {
- ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
- sal_uInt16 nErr = 0;
- if (aValIter.GetFirst(fVal, nErr))
- {
- // placed the loop on the inside for performance reasons:
- aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
- switch( eFunc )
- {
- case ifAVERAGE:
- case ifSUM:
- do
- {
- SetError(nErr);
- if ( bNull && fVal != 0.0 )
- {
- bNull = false;
- fMem = fVal;
- }
- else
- fRes += fVal;
- nCount++;
- }
- while (aValIter.GetNext(fVal, nErr));
- break;
- case ifSUMSQ:
- do
- {
- SetError(nErr);
- fRes += fVal * fVal;
- nCount++;
- }
- while (aValIter.GetNext(fVal, nErr));
- break;
- case ifPRODUCT:
- do
- {
- SetError(nErr);
- fRes *= fVal;
- nCount++;
- }
- while (aValIter.GetNext(fVal, nErr));
- break;
- case ifCOUNT:
- do
- {
- if ( !nErr )
- nCount++;
- }
- while (aValIter.GetNext(fVal, nErr));
- break;
- default: ; // nothing
- }
- SetError( nErr );
- }
- }
- }
- break;
- case svExternalDoubleRef:
- {
- ScMatrixRef pMat;
- PopExternalDoubleRef(pMat);
- if (nGlobalError)
- break;
-
- IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fRes, fMem, bNull);
- }
- break;
- case svMatrix :
- {
- ScMatrixRef pMat = PopMatrix();
- IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fRes, fMem, bNull);
- }
- break;
- case svError:
- {
- PopError();
- if ( eFunc == ifCOUNT )
- {
- nGlobalError = 0;
- }
- else if ( eFunc == ifCOUNT2 )
- {
- nCount++;
- nGlobalError = 0;
- }
- }
- break;
- default :
- while (nParamCount-- > 0)
- PopError();
- SetError(errIllegalParameter);
- }
- }
- switch( eFunc )
- {
- case ifSUM: fRes = ::rtl::math::approxAdd( fRes, fMem ); break;
- case ifAVERAGE: fRes = div(::rtl::math::approxAdd( fRes, fMem ), nCount); break;
- case ifCOUNT2:
- case ifCOUNT: fRes = nCount; break;
- case ifPRODUCT: if ( !nCount ) fRes = 0.0; break;
- default: ; // nothing
- }
- // Bei Summen etc. macht ein bool-Ergebnis keinen Sinn
- // und Anzahl ist immer Number (#38345#)
- if( eFunc == ifCOUNT || nFuncFmtType == NUMBERFORMAT_LOGICAL )
- nFuncFmtType = NUMBERFORMAT_NUMBER;
- return fRes;
-}
-
-
-void ScInterpreter::ScSumSQ()
-{
- RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumSQ" );
- PushDouble( IterateParameters( ifSUMSQ ) );
-}
-
-
-void ScInterpreter::ScSum()
-{
- short nParamCount = GetByte();
- double fRes = 0.0;
- double fVal = 0.0;
- ScAddress aAdr;
- ScRange aRange;
- size_t nRefInList = 0;
- while (nParamCount-- > 0)
- {
- switch (GetStackType())
- {
- case svString:
- {
- while (nParamCount-- > 0)
- Pop();
- SetError( errNoValue );
- }
- break;
- case svDouble :
- fVal = GetDouble();
- fRes += fVal;
- nFuncFmtType = NUMBERFORMAT_NUMBER;
- break;
- case svExternalSingleRef:
- {
- ScExternalRefCache::TokenRef pToken;
- ScExternalRefCache::CellFormat aFmt;
- PopExternalSingleRef(pToken, &aFmt);
-
- if (!pToken)
- break;
-
- StackVar eType = pToken->GetType();
- if (eType == formula::svDouble)
- {
- fVal = pToken->GetDouble();
- if (aFmt.mbIsSet)
- {
- nFuncFmtType = aFmt.mnType;
- nFuncFmtIndex = aFmt.mnIndex;
- }
-
- fRes += fVal;
- }
- }
- break;
- case svSingleRef :
- {
- PopSingleRef( aAdr );
-
- if (glSubTotal && pDok->RowFiltered( aAdr.Row(), aAdr.Tab()))
- {
- break;
- }
- ScRefCellValue aCell;
- aCell.assign(*pDok, aAdr);
- if (!aCell.isEmpty())
- {
- if (aCell.hasNumeric())
- {
- fVal = GetCellValue(aAdr, aCell);
- CurFmtToFuncFmt();
- fRes += fVal;
- }
- }
- }
- break;
- case svDoubleRef :
- case svRefList :
- {
- PopDoubleRef( aRange, nParamCount, nRefInList);
-
- sc::ColumnSpanSet aSet(false);
- aSet.set(aRange, true);
- if (glSubTotal)
- // Skip all filtered rows and subtotal formula cells.
- pDok->MarkSubTotalCells(aSet, aRange, false);
-
- FuncSum aAction;
- aSet.executeColumnAction(*pDok, aAction);
- fRes = aAction.getSum();
-
- // 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;
-
- sal_uLong nCount = 0;
- double fMem = 0.0;
- bool bNull = true;
- IterateMatrix(pMat, ifSUM, false, nCount, nFuncFmtType, fRes, fMem, bNull);
- fRes += fMem;
- }
- break;
- case svMatrix :
- {
- ScMatrixRef pMat = PopMatrix();
- sal_uLong nCount = 0;
- double fMem = 0.0;
- bool bNull = true;
- IterateMatrix(pMat, ifSUM, false, nCount, nFuncFmtType, fRes, fMem, bNull);
- fRes += fMem;
- }
- break;
- case svError:
- {
- PopError();
- }
- break;
- default :
- while (nParamCount-- > 0)
- PopError();
- SetError(errIllegalParameter);
- }
- }
-
- if (nFuncFmtType == NUMBERFORMAT_LOGICAL)
- nFuncFmtType = NUMBERFORMAT_NUMBER;
-
- PushDouble(fRes);
-}
-
-
-void ScInterpreter::ScProduct()
-{
- RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScProduct" );
- PushDouble( IterateParameters( ifPRODUCT ) );
-}
-
-
-void ScInterpreter::ScAverage( bool bTextAsZero )
-{
- RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAverage" );
- PushDouble( IterateParameters( ifAVERAGE, bTextAsZero ) );
-}
-
-void ScInterpreter::ScCount()
-{
- 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);
-}
-
-
-void ScInterpreter::ScCount2()
-{
- RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCount2" );
- PushDouble( IterateParameters( ifCOUNT2 ) );
-}
-
-
void ScInterpreter::GetStVarParams( double& rVal, double& rValCount,
bool bTextAsZero )
{
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index 7f712e3..e31a062 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -18,8 +18,17 @@
*/
-#include <rtl/logfile.hxx>
#include "interpre.hxx"
+#include "columnspanset.hxx"
+#include "column.hxx"
+#include "document.hxx"
+#include "cellvalue.hxx"
+#include "dociter.hxx"
+
+#include "formula/token.hxx"
+#include <rtl/logfile.hxx>
+
+using namespace formula;
double const fHalfMachEps = 0.5 * ::std::numeric_limits<double>::epsilon();
@@ -202,4 +211,768 @@ double ScInterpreter::GetGammaDist( double fX, double fAlpha, double fLambda )
return GetLowRegIGamma( fAlpha, fX / fLambda);
}
+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; }
+};
+
+class FuncSum : public sc::ColumnSpanSet::ColumnAction
+{
+ sc::ColumnBlockConstPosition maPos;
+ ScColumn* mpCol;
+ double mfSum;
+ sal_uInt32 mnNumFmt;
+
+public:
+ FuncSum() : mfSum(0.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;
+
+ mfSum += mpCol->SumNumericCells(maPos, nRow1, nRow2);
+ mnNumFmt = mpCol->GetNumberFormat(nRow2);
+ };
+
+ double getSum() const { return mfSum; }
+ sal_uInt32 getNumberFormat() const { return mnNumFmt; }
+};
+
+void IterateMatrix(
+ const ScMatrixRef& pMat, ScIterFunc eFunc, bool bTextAsZero,
+ sal_uLong& rCount, short& rFuncFmtType, double& fRes, double& fMem, bool& bNull)
+{
+ if (!pMat)
+ return;
+
+ rFuncFmtType = NUMBERFORMAT_NUMBER;
+ switch (eFunc)
+ {
+ case ifAVERAGE:
+ case ifSUM:
+ {
+ ScMatrix::IterateResult aRes = pMat->Sum(bTextAsZero);
+ if (bNull)
+ {
+ bNull = false;
+ fMem = aRes.mfFirst;
+ fRes += aRes.mfRest;
+ }
+ else
+ fRes += aRes.mfFirst + aRes.mfRest;
+ rCount += aRes.mnCount;
+ }
+ break;
+ case ifCOUNT:
+ rCount += pMat->Count(bTextAsZero);
+ break;
+ case ifCOUNT2:
+ rCount += pMat->Count(true);
+ break;
+ case ifPRODUCT:
+ {
+ ScMatrix::IterateResult aRes = pMat->Product(bTextAsZero);
+ fRes *= aRes.mfRest;
+ rCount += aRes.mnCount;
+ }
+ break;
+ case ifSUMSQ:
+ {
+ ScMatrix::IterateResult aRes = pMat->SumSquare(bTextAsZero);
+ fRes += aRes.mfRest;
+ rCount += aRes.mnCount;
+ }
+ break;
+ default:
+ ;
+ }
+}
+
+}
+
+double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IterateParameters" );
+ short nParamCount = GetByte();
+ double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
+ double fVal = 0.0;
+ double fMem = 0.0; // first numeric value.
+ bool bNull = true;
+ sal_uLong nCount = 0;
+ ScAddress aAdr;
+ ScRange aRange;
+ size_t nRefInList = 0;
+ if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
+ nGlobalError = 0;
+ while (nParamCount-- > 0)
+ {
+ switch (GetStackType())
+ {
+ case svString:
+ {
+ if( eFunc == ifCOUNT )
+ {
+ String aStr( PopString() );
+ sal_uInt32 nFIndex = 0; // damit default Land/Spr.
+ if ( bTextAsZero || pFormatter->IsNumberFormat(aStr, nFIndex, fVal))
+ nCount++;
+ }
+ else
+ {
+ switch ( eFunc )
+ {
+ case ifAVERAGE:
+ case ifSUM:
+ case ifSUMSQ:
+ case ifPRODUCT:
+ {
+ if ( bTextAsZero )
+ {
+ Pop();
+ nCount++;
+ if ( eFunc == ifPRODUCT )
+ fRes = 0.0;
+ }
+ else
+ {
+ while (nParamCount-- > 0)
+ Pop();
+ SetError( errNoValue );
+ }
+ }
+ break;
+ default:
+ Pop();
+ nCount++;
+ }
+ }
+ }
+ break;
+ case svDouble :
+ fVal = GetDouble();
+ nCount++;
+ switch( eFunc )
+ {
+ case ifAVERAGE:
+ case ifSUM:
+ if ( bNull && fVal != 0.0 )
+ {
+ bNull = false;
+ fMem = fVal;
+ }
+ else
+ fRes += fVal;
+ break;
+ case ifSUMSQ: fRes += fVal * fVal; break;
+ case ifPRODUCT: fRes *= fVal; break;
+ default: ; // nothing
+ }
+ nFuncFmtType = NUMBERFORMAT_NUMBER;
+ break;
+ case svExternalSingleRef:
+ {
+ ScExternalRefCache::TokenRef pToken;
+ ScExternalRefCache::CellFormat aFmt;
+ PopExternalSingleRef(pToken, &aFmt);
+ if (nGlobalError && (eFunc == ifCOUNT2 || eFunc == ifCOUNT))
+ {
+ nGlobalError = 0;
+ if ( eFunc == ifCOUNT2 )
+ ++nCount;
+ break;
+ }
+
+ if (!pToken)
+ break;
+
+ StackVar eType = pToken->GetType();
+ if (eFunc == ifCOUNT2)
+ {
+ if (eType != formula::svEmptyCell)
+ nCount++;
+ if (nGlobalError)
+ nGlobalError = 0;
+ }
+ else if (eType == formula::svDouble)
+ {
+ nCount++;
+ fVal = pToken->GetDouble();
+ if (aFmt.mbIsSet)
+ {
+ nFuncFmtType = aFmt.mnType;
+ nFuncFmtIndex = aFmt.mnIndex;
+ }
+ switch( eFunc )
+ {
+ case ifAVERAGE:
+ case ifSUM:
+ if ( bNull && fVal != 0.0 )
+ {
+ bNull = false;
+ fMem = fVal;
+ }
+ else
+ fRes += fVal;
+ break;
+ case ifSUMSQ: fRes += fVal * fVal; break;
+ case ifPRODUCT: fRes *= fVal; break;
+ case ifCOUNT:
+ if ( nGlobalError )
+ {
+ nGlobalError = 0;
+ nCount--;
+ }
+ break;
+ default: ; // nothing
+ }
+ }
+ else if (bTextAsZero && eType == formula::svString)
+ {
+ nCount++;
+ if ( eFunc == ifPRODUCT )
+ fRes = 0.0;
+ }
+ }
+ break;
+ case svSingleRef :
+ {
+ PopSingleRef( aAdr );
+ if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
+ {
+ nGlobalError = 0;
+ if ( eFunc == ifCOUNT2 )
+ ++nCount;
+ break;
+ }
+ if (glSubTotal && pDok->RowFiltered( aAdr.Row(), aAdr.Tab()))
+ {
+ break;
+ }
+ ScRefCellValue aCell;
+ aCell.assign(*pDok, aAdr);
+ if (!aCell.isEmpty())
+ {
+ if( eFunc == ifCOUNT2 )
+ {
+ CellType eCellType = aCell.meType;
+ if (eCellType != CELLTYPE_NONE)
+ nCount++;
+ if ( nGlobalError )
+ nGlobalError = 0;
+ }
+ else if (aCell.hasNumeric())
+ {
+ nCount++;
+ fVal = GetCellValue(aAdr, aCell);
+ CurFmtToFuncFmt();
+ switch( eFunc )
+ {
+ case ifAVERAGE:
+ case ifSUM:
+ if ( bNull && fVal != 0.0 )
+ {
+ bNull = false;
+ fMem = fVal;
+ }
+ else
+ fRes += fVal;
+ break;
+ case ifSUMSQ: fRes += fVal * fVal; break;
+ case ifPRODUCT: fRes *= fVal; break;
+ case ifCOUNT:
+ if ( nGlobalError )
+ {
+ nGlobalError = 0;
+ nCount--;
+ }
+ break;
+ default: ; // nothing
+ }
+ }
+ else if (bTextAsZero && aCell.hasString())
+ {
+ nCount++;
+ if ( eFunc == ifPRODUCT )
+ fRes = 0.0;
+ }
+ }
+ }
+ break;
+ case svDoubleRef :
+ case svRefList :
+ {
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+ if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
+ {
+ nGlobalError = 0;
+ if ( eFunc == ifCOUNT2 )
+ ++nCount;
+ break;
+ }
+ if( eFunc == ifCOUNT2 )
+ {
+ ScCellIterator aIter( pDok, aRange, glSubTotal );
+ for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
+ {
+ if (!aIter.hasEmptyData())
+ ++nCount;
+ }
+
+ if ( nGlobalError )
+ nGlobalError = 0;
+ }
+ else
+ {
+ ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
+ sal_uInt16 nErr = 0;
+ if (aValIter.GetFirst(fVal, nErr))
+ {
+ // placed the loop on the inside for performance reasons:
+ aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
+ switch( eFunc )
+ {
+ case ifAVERAGE:
+ case ifSUM:
+ do
+ {
+ SetError(nErr);
+ if ( bNull && fVal != 0.0 )
+ {
+ bNull = false;
+ fMem = fVal;
+ }
+ else
+ fRes += fVal;
+ nCount++;
+ }
+ while (aValIter.GetNext(fVal, nErr));
+ break;
+ case ifSUMSQ:
+ do
+ {
+ SetError(nErr);
+ fRes += fVal * fVal;
+ nCount++;
+ }
+ while (aValIter.GetNext(fVal, nErr));
+ break;
+ case ifPRODUCT:
+ do
+ {
+ SetError(nErr);
+ fRes *= fVal;
+ nCount++;
+ }
+ while (aValIter.GetNext(fVal, nErr));
+ break;
+ case ifCOUNT:
+ do
+ {
+ if ( !nErr )
+ nCount++;
+ }
+ while (aValIter.GetNext(fVal, nErr));
+ break;
+ default: ; // nothing
+ }
+ SetError( nErr );
+ }
+ }
+ }
+ break;
+ case svExternalDoubleRef:
+ {
+ ScMatrixRef pMat;
+ PopExternalDoubleRef(pMat);
+ if (nGlobalError)
+ break;
+
+ IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fRes, fMem, bNull);
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fRes, fMem, bNull);
+ }
+ break;
+ case svError:
+ {
+ PopError();
+ if ( eFunc == ifCOUNT )
+ {
+ nGlobalError = 0;
+ }
+ else if ( eFunc == ifCOUNT2 )
+ {
+ nCount++;
+ nGlobalError = 0;
+ }
+ }
+ break;
+ default :
+ while (nParamCount-- > 0)
+ PopError();
+ SetError(errIllegalParameter);
+ }
+ }
+ switch( eFunc )
+ {
+ case ifSUM: fRes = ::rtl::math::approxAdd( fRes, fMem ); break;
+ case ifAVERAGE: fRes = div(::rtl::math::approxAdd( fRes, fMem ), nCount); break;
+ case ifCOUNT2:
+ case ifCOUNT: fRes = nCount; break;
+ case ifPRODUCT: if ( !nCount ) fRes = 0.0; break;
+ default: ; // nothing
+ }
+ // Bei Summen etc. macht ein bool-Ergebnis keinen Sinn
+ // und Anzahl ist immer Number (#38345#)
+ if( eFunc == ifCOUNT || nFuncFmtType == NUMBERFORMAT_LOGICAL )
+ nFuncFmtType = NUMBERFORMAT_NUMBER;
+ return fRes;
+}
+
+
+void ScInterpreter::ScSumSQ()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumSQ" );
+ PushDouble( IterateParameters( ifSUMSQ ) );
+}
+
+
+void ScInterpreter::ScSum()
+{
+ short nParamCount = GetByte();
+ double fRes = 0.0;
+ double fVal = 0.0;
+ ScAddress aAdr;
+ ScRange aRange;
+ size_t nRefInList = 0;
+ while (nParamCount-- > 0)
+ {
+ switch (GetStackType())
+ {
+ case svString:
+ {
+ while (nParamCount-- > 0)
+ Pop();
+ SetError( errNoValue );
+ }
+ break;
+ case svDouble :
+ fVal = GetDouble();
+ fRes += fVal;
+ nFuncFmtType = NUMBERFORMAT_NUMBER;
+ break;
+ case svExternalSingleRef:
+ {
+ ScExternalRefCache::TokenRef pToken;
+ ScExternalRefCache::CellFormat aFmt;
+ PopExternalSingleRef(pToken, &aFmt);
+
+ if (!pToken)
+ break;
+
+ StackVar eType = pToken->GetType();
+ if (eType == formula::svDouble)
+ {
+ fVal = pToken->GetDouble();
+ if (aFmt.mbIsSet)
+ {
+ nFuncFmtType = aFmt.mnType;
+ nFuncFmtIndex = aFmt.mnIndex;
+ }
+
+ fRes += fVal;
+ }
+ }
+ break;
+ case svSingleRef :
+ {
+ PopSingleRef( aAdr );
+
+ if (glSubTotal && pDok->RowFiltered( aAdr.Row(), aAdr.Tab()))
+ {
+ break;
+ }
+ ScRefCellValue aCell;
+ aCell.assign(*pDok, aAdr);
+ if (!aCell.isEmpty())
+ {
+ if (aCell.hasNumeric())
+ {
+ fVal = GetCellValue(aAdr, aCell);
+ CurFmtToFuncFmt();
+ fRes += fVal;
+ }
+ }
+ }
+ break;
+ case svDoubleRef :
+ case svRefList :
+ {
+ PopDoubleRef( aRange, nParamCount, nRefInList);
+
+ sc::ColumnSpanSet aSet(false);
+ aSet.set(aRange, true);
+ if (glSubTotal)
+ // Skip all filtered rows and subtotal formula cells.
+ pDok->MarkSubTotalCells(aSet, aRange, false);
+
+ FuncSum aAction;
+ aSet.executeColumnAction(*pDok, aAction);
+ fRes = aAction.getSum();
+
+ // 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;
+
+ sal_uLong nCount = 0;
+ double fMem = 0.0;
+ bool bNull = true;
+ IterateMatrix(pMat, ifSUM, false, nCount, nFuncFmtType, fRes, fMem, bNull);
+ fRes += fMem;
+ }
+ break;
+ case svMatrix :
+ {
+ ScMatrixRef pMat = PopMatrix();
+ sal_uLong nCount = 0;
+ double fMem = 0.0;
+ bool bNull = true;
+ IterateMatrix(pMat, ifSUM, false, nCount, nFuncFmtType, fRes, fMem, bNull);
+ fRes += fMem;
+ }
+ break;
+ case svError:
+ {
+ PopError();
+ }
+ break;
+ default :
+ while (nParamCount-- > 0)
+ PopError();
+ SetError(errIllegalParameter);
+ }
+ }
+
+ if (nFuncFmtType == NUMBERFORMAT_LOGICAL)
+ nFuncFmtType = NUMBERFORMAT_NUMBER;
+
+ PushDouble(fRes);
+}
+
+
+void ScInterpreter::ScProduct()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScProduct" );
+ PushDouble( IterateParameters( ifPRODUCT ) );
+}
+
+
+void ScInterpreter::ScAverage( bool bTextAsZero )
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAverage" );
+ PushDouble( IterateParameters( ifAVERAGE, bTextAsZero ) );
+}
+
+void ScInterpreter::ScCount()
+{
+ 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);
+}
+
+
+void ScInterpreter::ScCount2()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCount2" );
+ PushDouble( IterateParameters( ifCOUNT2 ) );
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
More information about the Libreoffice-commits
mailing list