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

Kohei Yoshida kohei.yoshida at gmail.com
Tue Jul 2 19:09:41 PDT 2013


 sc/inc/formulacell.hxx               |   11 ++++++--
 sc/inc/types.hxx                     |    7 +++++
 sc/source/core/data/column2.cxx      |   20 ++++++++++++---
 sc/source/core/data/formulacell.cxx  |   46 ++++++++++++++++++++++++++++-------
 sc/source/core/tool/formulagroup.cxx |   10 +++----
 5 files changed, 75 insertions(+), 19 deletions(-)

New commits:
commit c205ba358f11b2a8997c980b554a20518cdf761a
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 487afcd..3879e99 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -54,6 +54,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 2af919dac0a267a55e967ff15fd2299ca0427e47
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;
 }


More information about the Libreoffice-commits mailing list