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

Kohei Yoshida kohei.yoshida at gmail.com
Fri Jun 28 08:32:20 PDT 2013


 sc/inc/column.hxx                   |    2 
 sc/inc/document.hxx                 |    2 
 sc/inc/table.hxx                    |    2 
 sc/source/core/data/column2.cxx     |  188 +++++++++++++++++++++++++++++++++---
 sc/source/core/data/document.cxx    |    2 
 sc/source/core/data/formulacell.cxx |   13 +-
 sc/source/core/data/table1.cxx      |    2 
 7 files changed, 188 insertions(+), 23 deletions(-)

New commits:
commit 49c16e6060b4323c79d33abfa163d4e5aae2bc15
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Fri Jun 28 11:29:14 2013 -0400

    Have FetchDoubleArray() to optionally calculate dependent formula cells.
    
    Change-Id: Ide29df664ff002f9cd8fe3edbf9512dd0cbb9eb6

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index b119d3d..4601ae2 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -471,7 +471,7 @@ public:
     formula::FormulaTokenRef ResolveStaticReference( SCROW nRow );
     bool ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 );
     void FillMatrix( ScMatrix& rMat, size_t nMatCol, SCROW nRow1, SCROW nRow2 ) const;
-    const double* FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW nRow1, SCROW nRow2 ) const;
+    const double* FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW nRow1, SCROW nRow2 );
     void SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen );
 
     void SetNumberFormat( SCROW nRow, sal_uInt32 nNumberFormat );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index fd8f61f..8d942b7 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1973,7 +1973,7 @@ public:
     formula::FormulaTokenRef ResolveStaticReference( const ScRange& rRange );
 
     const double* FetchDoubleArray(
-        sc::FormulaGroupContext& rCxt, const ScAddress& rPos, SCROW nLength ) const;
+        sc::FormulaGroupContext& rCxt, const ScAddress& rPos, SCROW nLength );
 
     SvtBroadcaster* GetBroadcaster( const ScAddress& rPos );
     const SvtBroadcaster* GetBroadcaster( const ScAddress& rPos ) const;
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index bae3818..bda039f 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -842,7 +842,7 @@ public:
     formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol, SCROW nRow );
     formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
     const double* FetchDoubleArray(
-        sc::FormulaGroupContext& rCxt, SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const;
+        sc::FormulaGroupContext& rCxt, SCCOL nCol, SCROW nRow1, SCROW nRow2 );
 
     ScRefCellValue GetRefCellValue( SCCOL nCol, SCROW nRow );
 
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 3704c6d..82990ab 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2073,23 +2073,189 @@ void ScColumn::FillMatrix( ScMatrix& rMat, size_t nMatCol, SCROW nRow1, SCROW nR
     sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
 }
 
-const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& /*rCxt*/, SCROW nRow1, SCROW nRow2 ) const
+namespace {
+
+bool appendDouble(
+    sc::FormulaGroupContext::DoubleArrayType& rArray, size_t nLen,
+    sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd )
 {
-    // TODO: I'll use the context object later.
-    if (nRow1 > nRow2)
-        return NULL;
+    size_t nLenRemain = nLen;
+    for (; it != itEnd; ++it)
+    {
+        switch (it->type)
+        {
+            case sc::element_type_numeric:
+            {
+                sc::numeric_block::iterator itData = sc::numeric_block::begin(*it->data);
+                sc::numeric_block::iterator itDataEnd;
+                if (nLenRemain >= it->size)
+                {
+                    // Block is shorter than the remaining requested length.
+                    itDataEnd = sc::numeric_block::end(*it->data);
+                    nLenRemain -= it->size;
+                }
+                else
+                {
+                    itDataEnd = itData;
+                    std::advance(itDataEnd, nLenRemain);
+                    nLenRemain = 0;
+                }
 
-    std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
-    if (aPos.first->type != sc::element_type_numeric)
-        // This is not a numeric cell block.
+                for (; itData != itDataEnd; ++itData)
+                    rArray.push_back(*itData);
+            }
+            break;
+            case sc::element_type_formula:
+            {
+                sc::formula_block::iterator itData = sc::formula_block::begin(*it->data);
+                sc::formula_block::iterator itDataEnd;
+                if (nLenRemain >= it->size)
+                {
+                    // Block is shorter than the remaining requested length.
+                    itDataEnd = sc::formula_block::end(*it->data);
+                    nLenRemain -= it->size;
+                }
+                else
+                {
+                    itDataEnd = itData;
+                    std::advance(itDataEnd, nLenRemain);
+                    nLenRemain = 0;
+                }
+
+                for (; itData != itDataEnd; ++itData)
+                {
+                    ScFormulaCell& rFC = **itData;
+                    rArray.push_back(rFC.GetValue());
+                }
+            }
+            break;
+            case sc::element_type_empty:
+            {
+                // Fill it with 0's.
+                if (nLenRemain >= it->size)
+                {
+                    rArray.resize(rArray.size() + it->size, 0);
+                    nLenRemain -= it->size;
+                }
+                else
+                {
+                    rArray.resize(rArray.size() + nLenRemain, 0);
+                    nLenRemain = 0;
+                }
+            }
+            break;
+            case sc::element_type_string:
+            case sc::element_type_edittext:
+            default:
+                return false;
+        }
+
+        if (!nLenRemain)
+            return true;
+    }
+
+    return false;
+}
+
+}
+
+const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW nRow1, SCROW nRow2 )
+{
+    if (nRow1 > nRow2)
         return NULL;
 
+    size_t nLenRequested = nRow2 - nRow1 + 1;
+    sc::CellStoreType::position_type aPos = maCells.position(nRow1);
     size_t nLen = aPos.first->size - aPos.second;
-    if (static_cast<SCROW>(nLen) < nRow2 - nRow1 + 1)
-        // Array shorter than requested.
-        return NULL;
+    switch (aPos.first->type)
+    {
+        case sc::element_type_numeric:
+        {
+            // This is a numeric cell block.
+            if (nLenRequested <= nLen)
+                // Requested length fits a single block.
+                return &sc::numeric_block::at(*aPos.first->data, aPos.second);
+
+            // Allocate a new array and copy the values to it.
+            sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aPos.first->data);
+            sc::numeric_block::const_iterator itEnd = sc::numeric_block::end(*aPos.first->data);
+            std::advance(it, aPos.second);
+            rCxt.maArrays.push_back(new sc::FormulaGroupContext::DoubleArrayType(it, itEnd));
+            sc::FormulaGroupContext::DoubleArrayType& rArray = rCxt.maArrays.back();
+            rArray.reserve(nLenRequested);
+
+            // Fill the remaining array with values from the following blocks.
+            ++aPos.first;
+            if (!appendDouble(rArray, nLenRequested - nLen, aPos.first, maCells.end()))
+                return NULL;
+
+            return &rArray[0];
+        }
+        break;
+        case sc::element_type_formula:
+        {
+            rCxt.maArrays.push_back(new sc::FormulaGroupContext::DoubleArrayType);
+            sc::FormulaGroupContext::DoubleArrayType& rArray = rCxt.maArrays.back();
+            rArray.reserve(nLenRequested);
+
+            sc::formula_block::const_iterator it = sc::formula_block::begin(*aPos.first->data);
+            sc::formula_block::const_iterator itEnd;
+            if (nLenRequested <= nLen)
+            {
+                // Requested length is within a single block.
+                itEnd = it;
+                std::advance(itEnd, nLenRequested);
+                for (; it != itEnd; ++it)
+                {
+                    ScFormulaCell& rCell = **it;
+                    rArray.push_back(rCell.GetValue()); // the cell may be interpreted.
+                }
+
+                return &rArray[0];
+            }
+
+            itEnd = sc::formula_block::end(*aPos.first->data);
+            std::advance(itEnd, nLenRequested);
+            for (; it != itEnd; ++it)
+            {
+                ScFormulaCell& rCell = **it;
+                rArray.push_back(rCell.GetValue()); // the cell may be interpreted.
+            }
+
+            // Fill the remaining array with values from the following blocks.
+            ++aPos.first;
+            if (!appendDouble(rArray, nLenRequested - nLen, aPos.first, maCells.end()))
+                return NULL;
+
+            return &rArray[0];
+        }
+        break;
+        case sc::element_type_empty:
+        {
+            if (nLenRequested <= nLen)
+            {
+                // Fill the whole length with zero.
+                rCxt.maArrays.push_back(new sc::FormulaGroupContext::DoubleArrayType(nLenRequested, 0.0));
+                return &rCxt.maArrays.back()[0];
+            }
+
+            // Fill the array with zero for the length of the empty block.
+            rCxt.maArrays.push_back(new sc::FormulaGroupContext::DoubleArrayType(nLen, 0.0));
+            sc::FormulaGroupContext::DoubleArrayType& rArray = rCxt.maArrays.back();
+            rArray.reserve(nLenRequested);
+
+            // Fill the remaining array with values from the following blocks.
+            ++aPos.first;
+            if (!appendDouble(rArray, nLenRequested - nLen, aPos.first, maCells.end()))
+                return NULL;
+
+            return &rArray[0];
+        }
+        default:
+            ;
+    }
 
-    return &sc::numeric_block::at(*aPos.first->data, aPos.second);
+    return NULL;
 }
 
 void ScColumn::SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen )
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 3ed67c3..3ce424f 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1609,7 +1609,7 @@ formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRan
 }
 
 const double* ScDocument::FetchDoubleArray(
-    sc::FormulaGroupContext& rCxt, const ScAddress& rPos, SCROW nLength ) const
+    sc::FormulaGroupContext& rCxt, const ScAddress& rPos, SCROW nLength )
 {
     SCTAB nTab = rPos.Tab();
     if (!TableExists(nTab))
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 2ade13b..26d7ee5 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2941,13 +2941,13 @@ namespace {
 
 class GroupTokenConverter
 {
-    sc::FormulaGroupContext maCxt;
+    sc::FormulaGroupContext& mrCxt;
     ScTokenArray& mrGroupTokens;
     ScDocument& mrDoc;
     ScFormulaCell& mrCell;
 public:
-    GroupTokenConverter(ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell) :
-        mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell) {}
+    GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell) :
+        mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell) {}
 
     bool convert(ScTokenArray& rCode)
     {
@@ -2978,7 +2978,7 @@ public:
                         // we finish cell storage rework, we'll support temporary
                         // generation of a double array which is a combination of
                         // multiple cell array segments.
-                        const double* pArray = mrDoc.FetchDoubleArray(maCxt, aRefPos, mrCell.GetCellGroup()->mnLength);
+                        const double* pArray = mrDoc.FetchDoubleArray(mrCxt, aRefPos, mrCell.GetCellGroup()->mnLength);
                         if (!pArray)
                             return false;
 
@@ -3020,7 +3020,7 @@ public:
                         for (SCCOL i = aRef.Ref1.nCol; i <= aRef.Ref2.nCol; ++i)
                         {
                             aRefPos.SetCol(i);
-                            const double* pArray = mrDoc.FetchDoubleArray(maCxt, aRefPos, nArrayLength);
+                            const double* pArray = mrDoc.FetchDoubleArray(mrCxt, aRefPos, nArrayLength);
                             if (!pArray)
                                 return false;
 
@@ -3108,9 +3108,8 @@ bool ScFormulaCell::InterpretFormulaGroup()
         return InterpretInvariantFormulaGroup();
 
     sc::FormulaGroupContext aCxt;
-
     ScTokenArray aCode;
-    GroupTokenConverter aConverter(aCode, *pDocument, *this);
+    GroupTokenConverter aConverter(aCxt, aCode, *pDocument, *this);
     if (!aConverter.convert(*pCode))
         return false;
     return sc::FormulaGroupInterpreter::getStatic()->interpret(*pDocument, aPos, xGroup, aCode);
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 2d90fa9..dcd0344 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2156,7 +2156,7 @@ formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol1, SCROW nRo
 }
 
 const double* ScTable::FetchDoubleArray(
-    sc::FormulaGroupContext& rCxt, SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
+    sc::FormulaGroupContext& rCxt, SCCOL nCol, SCROW nRow1, SCROW nRow2 )
 {
     if (nRow2 < nRow1)
         return NULL;


More information about the Libreoffice-commits mailing list