sc/inc/column.hxx | 1 sc/inc/formulacell.hxx | 5 sc/inc/token.hxx | 13 -- sc/source/core/data/column.cxx | 56 ++++++++- sc/source/core/data/formulacell.cxx | 5 sc/source/core/tool/interpr1.cxx | 219 ++++++++++++++++++++++++++++++------ sc/source/core/tool/token.cxx | 12 + 7 files changed, 258 insertions(+), 53 deletions(-)
New commits: commit e603b646f3cd4f0b7ffbf6aa206f476923d2a3ff Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Tue Jul 2 00:51:10 2013 -0400 Re-implement SUM function to make use of new cell storage. And fix a bug in my new COUNT function, where I forgot to tally numeric formula cells. Change-Id: I52d26be3e48f646f656821066e23594d52f78c6d diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 7ce53ad..359b8ac 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -409,6 +409,7 @@ 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( diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 8d3f625..64aae03 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -468,18 +468,57 @@ 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) + void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize) { - if (rNode.type != sc::element_type_numeric) - return; - - mnCount += 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.IsValue()) + ++mnCount; + } + } + break; + default: + ; + } } size_t getCount() const { return mnCount; } @@ -487,6 +526,13 @@ public: } +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; diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index f8acd73..d02a0bc 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -3854,6 +3854,64 @@ void ScInterpreter::ScMax( bool 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; } +}; + +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) @@ -4258,8 +4316,132 @@ void ScInterpreter::ScSumSQ() void ScInterpreter::ScSum() { - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSum" ); - PushDouble( IterateParameters( ifSUM ) ); + 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); } @@ -4276,39 +4458,6 @@ 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() { short nParamCount = GetByte(); commit c35d63292d08bef1825b179a00cbc876c99a3887 Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Tue Jul 2 00:06:22 2013 -0400 Put the matrix header back in for Windows build... Change-Id: I676b3d9b702af51bf00dff9ef55d16e7fbdec65e diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index 1f9b960..a63025c 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -259,10 +259,7 @@ public: const formula::FormulaGrammar::Grammar eGrammar ) { aResult.SetHybridFormula( r); eTempGrammar = eGrammar; } - void SetResultMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL ) - { - aResult.SetMatrix(nCols, nRows, pMat, pUL); - } + void SetResultMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL ); /** For import only: set a double result. Use this instead of SetHybridDouble() if there is no (temporary) diff --git a/sc/inc/token.hxx b/sc/inc/token.hxx index 116022a..0839326 100644 --- a/sc/inc/token.hxx +++ b/sc/inc/token.hxx @@ -30,7 +30,7 @@ #include "scdllapi.h" #include "formula/IFunctionDescription.hxx" #include "formula/token.hxx" -#include "types.hxx" +#include "scmatrix.hxx" class ScJumpMatrix; @@ -318,7 +318,7 @@ public: virtual const String & GetString() const; virtual const ScMatrix* GetMatrix() const; virtual bool operator==( const formula::FormulaToken& rToken ) const; - virtual FormulaToken* Clone() const { return new ScMatrixCellResultToken(*this); } + virtual FormulaToken* Clone() const; formula::StackVar GetUpperLeftType() const { return xUpperLeft ? @@ -357,12 +357,9 @@ public: SCCOL GetMatCols() const { return nCols; } SCROW GetMatRows() const { return nRows; } - /** Assign matrix result, keep matrix formula - dimension. */ - void Assign( const ScMatrixCellResultToken & r ) - { - ScMatrixCellResultToken::Assign( r); - } + /** Assign matrix result, keep matrix formula + dimension. */ + void Assign( const ScMatrixCellResultToken & r ); /** Assign any result, keep matrix formula dimension. If token is of type diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index f2d72da..1e86cfc 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -1591,6 +1591,11 @@ void ScFormulaCell::SetResultToken( const formula::FormulaToken* pToken ) aResult.SetToken(pToken); } +void ScFormulaCell::SetResultMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL ) +{ + aResult.SetMatrix(nCols, nRows, pMat, pUL); +} + void ScFormulaCell::SetErrCode( sal_uInt16 n ) { /* FIXME: check the numerous places where ScTokenArray::GetCodeError() is diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index 3f40fa7..ad8fdf2 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -37,7 +37,6 @@ #include "rangeseq.hxx" #include "externalrefmgr.hxx" #include "document.hxx" -#include "scmatrix.hxx" using ::std::vector; @@ -1060,6 +1059,11 @@ bool ScMatrixCellResultToken::operator==( const FormulaToken& r ) const xMatrix == static_cast<const ScMatrixCellResultToken &>(r).xMatrix; } +FormulaToken* ScMatrixCellResultToken::Clone() const +{ + return new ScMatrixCellResultToken(*this); +} + void ScMatrixCellResultToken::Assign( const ScMatrixCellResultToken & r ) { xMatrix = r.xMatrix; @@ -1088,6 +1092,12 @@ bool ScMatrixFormulaCellToken::operator==( const FormulaToken& r ) const return p && ScMatrixCellResultToken::operator==( r ) && nCols == p->nCols && nRows == p->nRows; } + +void ScMatrixFormulaCellToken::Assign( const ScMatrixCellResultToken & r ) +{ + ScMatrixCellResultToken::Assign( r); +} + void ScMatrixFormulaCellToken::Assign( const formula::FormulaToken& r ) { if (this == &r) _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits