[Libreoffice-commits] core.git: Branch 'feature/calc-group-interpreter' - sc/source

Kohei Yoshida kohei.yoshida at gmail.com
Tue Jul 2 12:50:14 PDT 2013


 sc/source/core/tool/interpr1.cxx |  763 --------------------------------------
 sc/source/core/tool/interpr6.cxx |  775 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 774 insertions(+), 764 deletions(-)

New commits:
commit 8834366734fa84667ffd43c4725274a3995d5517
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....
    
    Conflicts:
    	sc/source/core/tool/interpr1.cxx
    
    Change-Id: Ic3e4879daebd09c8dcb86a42b305864dcc1c67c4

diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index af83cfb..1c10c0b 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -57,8 +57,6 @@
 #include "queryparam.hxx"
 #include "queryentry.hxx"
 #include "tokenarray.hxx"
-#include "columnspanset.hxx"
-#include "column.hxx"
 
 #include <comphelper/processfactory.hxx>
 #include <comphelper/string.hxx>
@@ -3851,767 +3849,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;
-                }
-                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