[Libreoffice-commits] core.git: Branch 'feature/formula-core-rework' - include/formula sc/inc sc/source

Kohei Yoshida kohei.yoshida at gmail.com
Fri Apr 26 19:52:38 PDT 2013


 include/formula/token.hxx           |    8 --
 include/formula/types.hxx           |   35 ++++++++++
 sc/inc/column.hxx                   |    7 +-
 sc/inc/document.hxx                 |   11 ---
 sc/inc/formulacell.hxx              |    2 
 sc/inc/table.hxx                    |    4 -
 sc/inc/token.hxx                    |    4 -
 sc/inc/types.hxx                    |    3 
 sc/source/core/data/column2.cxx     |   70 +++++++++++++++++---
 sc/source/core/data/document.cxx    |   16 +++-
 sc/source/core/data/formulacell.cxx |  126 ++++++++++++++++++++++++------------
 sc/source/core/data/table1.cxx      |   28 ++++++--
 12 files changed, 234 insertions(+), 80 deletions(-)

New commits:
commit ab4299e4f2af15ef229dfc5f16a4bcd1668d5016
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Fri Apr 26 22:53:04 2013 -0400

    Handle invariant group with single references.
    
    Change-Id: Ifbbac2b11b1023a5cf3d21204c12b9740af09aaf

diff --git a/include/formula/token.hxx b/include/formula/token.hxx
index 3a174d7..82bdf7f 100644
--- a/include/formula/token.hxx
+++ b/include/formula/token.hxx
@@ -27,8 +27,7 @@
 #include <tools/mempool.hxx>
 #include "formula/IFunctionDescription.hxx"
 #include "formula/formuladllapi.h"
-
-#include <boost/intrusive_ptr.hpp>
+#include "formula/types.hxx"
 
 namespace formula
 {
@@ -79,11 +78,6 @@ typedef sal_uInt8 StackVar;
 typedef StackVarEnum StackVar;
 #endif
 
-
-class FormulaToken;
-typedef ::boost::intrusive_ptr<FormulaToken>        FormulaTokenRef;
-typedef ::boost::intrusive_ptr<const FormulaToken>  FormulaConstTokenRef;
-
 class FormulaTokenArray;
 
 class FORMULA_DLLPUBLIC FormulaToken : public IFormulaToken
diff --git a/include/formula/types.hxx b/include/formula/types.hxx
new file mode 100644
index 0000000..33ead51
--- /dev/null
+++ b/include/formula/types.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef FORMULA_TYPES_HXX
+#define FORMULA_TYPES_HXX
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace formula {
+
+class FormulaToken;
+typedef ::boost::intrusive_ptr<FormulaToken>        FormulaTokenRef;
+typedef ::boost::intrusive_ptr<const FormulaToken>  FormulaConstTokenRef;
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 866fce3..157bc17 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -25,11 +25,13 @@
 #include "address.hxx"
 #include "rangenam.hxx"
 #include "types.hxx"
-#include <boost/intrusive_ptr.hpp>
+#include "formula/types.hxx"
 
 #include <set>
 #include <vector>
 
+#include <boost/intrusive_ptr.hpp>
+
 #define DEBUG_COLUMN_STORAGE 0
 
 #if DEBUG_COLUMN_STORAGE
@@ -448,7 +450,8 @@ public:
     size_t GetFormulaHash( SCROW nRow ) const;
 
     ScFormulaVectorState GetFormulaVectorState( SCROW nRow ) const;
-    bool ResolveVectorReference( SCROW nRow1, SCROW nRow2 );
+    formula::FormulaTokenRef ResolveStaticReference( SCROW nRow );
+    bool ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 );
 
     ScRefCellValue GetRefCellValue( SCROW );
 
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 052b81d..cdb80e0 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -32,6 +32,7 @@
 #include "sortparam.hxx"
 #include "types.hxx"
 #include "formula/grammar.hxx"
+#include "formula/types.hxx"
 #include <com/sun/star/chart2/XChartDocument.hpp>
 #include "typedstrdata.hxx"
 #include "compressedarray.hxx"
@@ -1940,14 +1941,8 @@ public:
 
     ScFormulaVectorState GetFormulaVectorState( const ScAddress& rPos ) const;
 
-    /**
-     * Check if the range contains any "dirty" formula cells.  In the future
-     * we'll use this function to interpret those "dirty" formula cells on
-     * demand.
-     *
-     * @return true if the range is totally clean, false otherwise.
-     */
-    bool ResolveVectorReference( const ScAddress& rPos, SCROW nEndRow );
+    formula::FormulaTokenRef ResolveStaticReference( const ScAddress& rPos );
+    formula::FormulaTokenRef ResolveStaticReference( const ScRange& rRange );
 
 private: // CLOOK-Impl-methods
 
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index e6239e3..397fd9c 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -282,6 +282,8 @@ public:
      */
     void            SetResultDouble( double n )     { aResult.SetDouble( n); }
 
+    double GetResultDouble() const { return aResult.GetDouble(); }
+
     void            SetErrCode( sal_uInt16 n );
     bool IsHyperLinkCell() const;
     EditTextObject* CreateURLObject();
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index eb5f756..c04b902 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -30,6 +30,7 @@
 #include "compressedarray.hxx"
 #include "postit.hxx"
 #include "types.hxx"
+#include "formula/types.hxx"
 
 #include <set>
 #include <map>
@@ -819,7 +820,8 @@ public:
     size_t GetFormulaHash( SCCOL nCol, SCROW nRow ) const;
 
     ScFormulaVectorState GetFormulaVectorState( SCCOL nCol, SCROW nRow ) const;
-    bool ResolveVectorReference( SCCOL nCol, SCROW nRow1, SCROW nRow2 );
+    formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol, SCROW nRow );
+    formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
 
     ScRefCellValue GetRefCellValue( SCCOL nCol, SCROW nRow );
 
diff --git a/sc/inc/token.hxx b/sc/inc/token.hxx
index a540555..abd3cd5 100644
--- a/sc/inc/token.hxx
+++ b/sc/inc/token.hxx
@@ -31,13 +31,11 @@
 #include "scdllapi.h"
 #include "formula/IFunctionDescription.hxx"
 #include "formula/token.hxx"
-
+#include "types.hxx"
 
 class ScJumpMatrix;
-class ScToken;
 
 typedef ::std::vector< ScComplexRefData > ScRefList;
-typedef ::boost::intrusive_ptr<ScToken> ScTokenRef;
 
 class SC_DLLPUBLIC ScToken : public formula::FormulaToken
 {
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 99d78f4..aa20043 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -36,6 +36,9 @@ class ScMatrix;
 typedef ::boost::intrusive_ptr<ScMatrix>        ScMatrixRef;
 typedef ::boost::intrusive_ptr<const ScMatrix>  ScConstMatrixRef;
 
+class ScToken;
+typedef ::boost::intrusive_ptr<ScToken> ScTokenRef;
+
 /**
  * When vectorization is enabled, we could potentially mass-calculate a
  * series of formula token arrays in adjacent formula cells in one step,
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index e95dcf9..20483f8 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1589,28 +1589,78 @@ ScFormulaVectorState ScColumn::GetFormulaVectorState( SCROW nRow ) const
     return pCell ? pCell->GetVectorState() : FormulaVectorUnknown;
 }
 
-bool ScColumn::ResolveVectorReference( SCROW nRow1, SCROW nRow2 )
+formula::FormulaTokenRef ScColumn::ResolveStaticReference( SCROW nRow )
 {
     std::vector<ColEntry>::iterator itEnd = maItems.end();
     // Find first cell whose position is equal or greater than nRow1.
     ColEntry aBound;
-    aBound.nRow = nRow1;
+    aBound.nRow = nRow;
     std::vector<ColEntry>::iterator it =
         std::lower_bound(maItems.begin(), itEnd, aBound, ColEntry::Less());
 
-    if (it == itEnd)
+    if (it == itEnd || it->nRow != nRow)
+    {
+        // Empty cell.
+        return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
+    }
+
+    ScBaseCell* pCell = it->pCell;
+    switch (pCell->GetCellType())
+    {
+        case CELLTYPE_VALUE:
+        {
+            ScValueCell* pVC = static_cast<ScValueCell*>(pCell);
+            return formula::FormulaTokenRef(new formula::FormulaDoubleToken(pVC->GetValue()));
+        }
+        case CELLTYPE_FORMULA:
+        {
+            ScFormulaCell* pFC = static_cast<ScFormulaCell*>(pCell);
+            if (pFC->GetDirty())
+                // Dirty formula cell is not considered static. Return null token.
+                return formula::FormulaTokenRef();
+
+            return formula::FormulaTokenRef(new formula::FormulaDoubleToken(pFC->GetResultDouble()));
+        }
+        default:
+            ;
+    }
+
+    return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
+}
+
+bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 )
+{
+    if (nRow1 > nRow2)
         return false;
 
+    std::vector<ColEntry>::iterator itEnd = maItems.end();
+    // Find first cell whose position is equal or greater than nRow1.
+    ColEntry aBound;
+    aBound.nRow = nRow1;
+    std::vector<ColEntry>::iterator it =
+        std::lower_bound(maItems.begin(), itEnd, aBound, ColEntry::Less());
+
     for (; it != itEnd && it->nRow <= nRow2; ++it)
     {
-        if (it->pCell->GetCellType() != CELLTYPE_FORMULA)
-            // Non-formula cells are fine.
-            continue;
+        switch (it->pCell->GetCellType())
+        {
+            case CELLTYPE_VALUE:
+            {
+                ScValueCell* pVC = static_cast<ScValueCell*>(it->pCell);
+                rMat.PutDouble(pVC->GetValue(), nMatCol, it->nRow - nRow1);
+            }
+            case CELLTYPE_FORMULA:
+            {
+                ScFormulaCell* pFC = static_cast<ScFormulaCell*>(it->pCell);
+                if (pFC->GetDirty())
+                    // Dirty formula cell is not considered static. Return null token.
+                    return false;
 
-        ScFormulaCell* pFC = static_cast<ScFormulaCell*>(it->pCell);
-        if (pFC->GetDirty())
-            // Dirty formula cells are not supported yet.
-            return false;
+                rMat.PutDouble(pFC->GetResultDouble(), nMatCol, it->nRow - nRow1);
+            }
+            default:
+                ;
+        }
     }
 
     return true;
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 6a00d36..9a3dcf7 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1574,13 +1574,23 @@ ScFormulaVectorState ScDocument::GetFormulaVectorState( const ScAddress& rPos )
     return maTabs[nTab]->GetFormulaVectorState(rPos.Col(), rPos.Row());
 }
 
-bool ScDocument::ResolveVectorReference( const ScAddress& rPos, SCROW nEndRow )
+formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScAddress& rPos )
 {
     SCTAB nTab = rPos.Tab();
     if (!TableExists(nTab))
-        return false;
+        return formula::FormulaTokenRef();
+
+    return maTabs[nTab]->ResolveStaticReference(rPos.Col(), rPos.Row());
+}
+
+formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRange )
+{
+    SCTAB nTab = rRange.aStart.Tab();
+    if (nTab != rRange.aEnd.Tab() || !TableExists(nTab))
+        return formula::FormulaTokenRef();
 
-    return maTabs[nTab]->ResolveVectorReference(rPos.Col(), rPos.Row(), nEndRow);
+    return maTabs[nTab]->ResolveStaticReference(
+        rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
 }
 
 bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index e73641d..43d80cf 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2954,27 +2954,75 @@ bool ScFormulaCell::InterpretFormulaGroup()
     switch (pCode->GetVectorState())
     {
         case FormulaVectorEnabled:
+        case FormulaVectorCheckReference:
             // Good.
         break;
-        case FormulaVectorCheckReference:
-            // To support this we would need a real range-based dependency
-            // tracking. We can't support this right now.
-            return false;
         case FormulaVectorDisabled:
         case FormulaVectorUnknown:
         default:
+            // Not good.
             return false;
     }
 
-//    fprintf( stderr, "Interpret cell %d, %d\n", (int)aPos.Col(), (int)aPos.Row() );
-
     if (xGroup->mbInvariant)
     {
-//        fprintf( stderr, "struck gold - completely invariant for %d items !\n",
-//                 (int)xGroup->mnLength );
+        if (pCode->GetVectorState() == FormulaVectorCheckReference)
+        {
+            // An invariant group should only have absolute references, and no
+            // external references are allowed.
+
+            ScTokenArray aCode;
+            pCode->Reset();
+            for (const formula::FormulaToken* p = pCode->First(); p; p = pCode->Next())
+            {
+                const ScToken* pToken = static_cast<const ScToken*>(p);
+                switch (pToken->GetType())
+                {
+                    case svSingleRef:
+                    {
+                        const ScSingleRefData& rRef = pToken->GetSingleRef();
+                        ScAddress aRefPos(rRef.nCol, rRef.nRow, rRef.nTab);
+                        formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefPos);
+                        if (!pNewToken)
+                            return false;
+
+                        aCode.AddToken(*pNewToken);
+                    }
+                    break;
+                    case svDoubleRef:
+                    {
+                        const ScComplexRefData& rRef = pToken->GetDoubleRef();
+                        ScRange aRefRange(
+                            rRef.Ref1.nCol, rRef.Ref1.nRow, rRef.Ref1.nTab,
+                            rRef.Ref2.nCol, rRef.Ref2.nRow, rRef.Ref2.nTab);
+
+                        formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefRange);
+                        if (!pNewToken)
+                            return false;
+
+                        aCode.AddToken(*pNewToken);
+                    }
+                    break;
+                    default:
+                        aCode.AddToken(*pToken);
+                }
+            }
+
+            ScCompiler aComp(pDocument, aPos, aCode);
+            aComp.SetGrammar(pDocument->GetGrammar());
+            aComp.CompileTokenArray(); // Create RPN token array.
+            ScInterpreter aInterpreter(this, pDocument, aPos, aCode);
+            aInterpreter.Interpret();
+            aResult.SetToken(aInterpreter.GetResultToken().get());
+        }
+        else
+        {
+            // Formula contains no references.
+            ScInterpreter aInterpreter(this, pDocument, aPos, *pCode);
+            aInterpreter.Interpret();
+            aResult.SetToken(aInterpreter.GetResultToken().get());
+        }
 
-        // calculate ourselves:
-        InterpretTail( SCITP_NORMAL );
         for ( sal_Int32 i = 0; i < xGroup->mnLength; i++ )
         {
             ScAddress aTmpPos = aPos;
@@ -2993,37 +3041,35 @@ bool ScFormulaCell::InterpretFormulaGroup()
         }
         return true;
     }
-    else
-    {
-        // scan the formula ...
-        // have a document method: "Get2DRangeAsDoublesArray" that does the
-        // column-based heavy lifting call it for each absolute range from the
-        // first cell pos in the formula group.
-        //
-        // Project single references to ranges by adding their vector * xGroup->mnLength
-        //
-        // TODO:
-        //    elide multiple dimensional movement in vectors eg. =SUM(A1<1,1>)
-        //    produces a diagonal 'column' that serves no useful purpose for us.
-        //    these should be very rare. Should elide in GetDeltas anyway and
-        //    assert here.
-        //
-        // Having built our input data ...
-        // Throw it, and the formula over to some 'OpenCLCalculage' hook
-        //
-        // on return - release references on these double buffers
-        //
-        // transfer the result to the formula cells (as above)
-        // store the doubles in the columns' maDoubles array for
-        // dependent formulae
-        //
-        // TODO:
-        //    need to abort/fail when we get errors returned and fallback to
-        //    stock interpreting [ I guess ], unless we can use NaN etc. to
-        //    signal errors.
 
-        return false;
-    }
+    // scan the formula ...
+    // have a document method: "Get2DRangeAsDoublesArray" that does the
+    // column-based heavy lifting call it for each absolute range from the
+    // first cell pos in the formula group.
+    //
+    // Project single references to ranges by adding their vector * xGroup->mnLength
+    //
+    // TODO:
+    //    elide multiple dimensional movement in vectors eg. =SUM(A1<1,1>)
+    //    produces a diagonal 'column' that serves no useful purpose for us.
+    //    these should be very rare. Should elide in GetDeltas anyway and
+    //    assert here.
+    //
+    // Having built our input data ...
+    // Throw it, and the formula over to some 'OpenCLCalculage' hook
+    //
+    // on return - release references on these double buffers
+    //
+    // transfer the result to the formula cells (as above)
+    // store the doubles in the columns' maDoubles array for
+    // dependent formulae
+    //
+    // TODO:
+    //    need to abort/fail when we get errors returned and fallback to
+    //    stock interpreting [ I guess ], unless we can use NaN etc. to
+    //    signal errors.
+
+    return false;
 }
 
 void ScFormulaCell::StartListeningTo( ScDocument* pDoc )
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 7ae3c66..52e0bb9 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2113,15 +2113,31 @@ ScFormulaVectorState ScTable::GetFormulaVectorState( SCCOL nCol, SCROW nRow ) co
     return aCol[nCol].GetFormulaVectorState(nRow);
 }
 
-bool ScTable::ResolveVectorReference( SCCOL nCol, SCROW nRow1, SCROW nRow2 )
+formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol, SCROW nRow )
 {
-    if (!ValidCol(nCol) || !ValidRow(nRow1) || !ValidRow(nRow2))
-        return false;
+    if (!ValidCol(nCol) || !ValidRow(nRow))
+        return formula::FormulaTokenRef();
 
-    if (!aCol[nCol].ResolveVectorReference(nRow1, nRow2))
-        return false;
+    return aCol[nCol].ResolveStaticReference(nRow);
+}
 
-    return true;
+formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+    if (nCol2 < nCol1 || nRow2 < nRow1)
+        return formula::FormulaTokenRef();
+
+    if (!ValidCol(nCol1) || !ValidCol(nCol2) || !ValidRow(nRow1) || !ValidRow(nRow2))
+        return formula::FormulaTokenRef();
+
+    ScMatrixRef pMat(new ScMatrix(nCol2-nCol1+1, nRow2-nRow1+1, 0.0));
+    for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+    {
+        if (!aCol[nCol].ResolveStaticReference(*pMat, nCol2-nCol1, nRow1, nRow2))
+            // Column contains non-static cell. Failed.
+            return formula::FormulaTokenRef();
+    }
+
+    return formula::FormulaTokenRef(new ScMatrixToken(pMat));
 }
 
 ScRefCellValue ScTable::GetRefCellValue( SCCOL nCol, SCROW nRow )


More information about the Libreoffice-commits mailing list