[Libreoffice-commits] core.git: 12 commits - formula/source include/formula sc/inc sc/source

Kohei Yoshida kohei.yoshida at collabora.com
Tue Sep 10 08:45:55 PDT 2013


 formula/source/core/api/vectortoken.cxx  |    2 
 include/formula/vectortoken.hxx          |    4 
 sc/inc/column.hxx                        |    1 
 sc/inc/document.hxx                      |   12 ++
 sc/inc/formulacell.hxx                   |    1 
 sc/inc/formulagroup.hxx                  |    7 +
 sc/inc/formularesult.hxx                 |    1 
 sc/inc/table.hxx                         |    2 
 sc/source/core/data/column2.cxx          |  186 +++++++++++++++++++++++++------
 sc/source/core/data/document.cxx         |    9 +
 sc/source/core/data/formulacell.cxx      |   40 ++++++
 sc/source/core/data/table1.cxx           |   15 ++
 sc/source/core/opencl/formulagroupcl.cxx |   33 ++---
 sc/source/core/tool/formulagroup.cxx     |  142 ++++++++++++++++++++++-
 sc/source/core/tool/formularesult.cxx    |   49 ++++++++
 sc/source/core/tool/interpr6.cxx         |    2 
 16 files changed, 442 insertions(+), 64 deletions(-)

New commits:
commit a66aeace78f366800ba5bc8be0d334ea823179ab
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Sep 10 11:16:22 2013 -0400

    Add ability to specify starting row when querying for last non-empty row.
    
    And it can only go upwards from there.
    
    Change-Id: I4c8037f687dfdd0b6c937463696d628e78e4a8bf

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index ba79c23..6d09ad1 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -184,6 +184,7 @@ public:
     bool               HasVisibleDataAt(SCROW nRow) const;
     SCROW              GetFirstDataPos() const;
     SCROW              GetLastDataPos() const;
+    SCROW GetLastDataPos( SCROW nLastRow ) const;
     bool               GetPrevDataPos(SCROW& rRow) const;
     bool               GetNextDataPos(SCROW& rRow) const;
     void               FindDataAreaPos(SCROW& rRow, bool bDown) const; // (without Broadcaster)
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 4cbf06a..6993abb 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1028,11 +1028,16 @@ public:
                                           SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const;
 
     /**
-     * Return the last non-empty row position in given columns, or 0 if the
-     * columns are empty. A negative value is returned if the given sheet or
-     * column positions are invalid.
+     * Return the last non-empty row position in given columns that's no
+     * greater than the initial last row position, or 0 if the columns are
+     * empty. A negative value is returned if the given sheet or column
+     * positions are invalid.
+     *
+     * <p>It starts from the specified last row position, and finds the first
+     * non-empty row position in the upward direction if the start row
+     * position is empty.</p>
      */
-    SCROW GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2 ) const;
+    SCROW GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nLastRow ) const;
 
     SC_DLLPUBLIC void           GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
                                     SCCOL& rEndCol, SCROW& rEndRow, bool bIncludeOld, bool bOnlyDown ) const;
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 9bf3f90..fc8ae3a 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -469,7 +469,7 @@ public:
     bool        ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rStartRow,
                                       SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const;
 
-    SCROW GetLastDataRow( SCCOL nCol1, SCCOL nCol2 ) const;
+    SCROW GetLastDataRow( SCCOL nCol1, SCCOL nCol2, SCROW nLastRow ) const;
 
     SCSIZE      GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
                                         SCCOL nEndCol, SCROW nEndRow, ScDirection eDir ) const;
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 42c5469..eda83ff 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1255,6 +1255,19 @@ SCROW ScColumn::GetLastDataPos() const
     return MAXROW - static_cast<SCROW>(it->size);
 }
 
+SCROW ScColumn::GetLastDataPos( SCROW nLastRow ) const
+{
+    sc::CellStoreType::const_position_type aPos = maCells.position(nLastRow);
+    if (aPos.first->type != sc::element_type_empty)
+        return nLastRow;
+
+    if (aPos.first == maCells.begin())
+        // This is the first block, and is empty.
+        return 0;
+
+    return static_cast<SCROW>(aPos.first->position - 1);
+}
+
 bool ScColumn::GetPrevDataPos(SCROW& rRow) const
 {
     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 7bda1da..dc7db44 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1018,13 +1018,13 @@ bool ScDocument::ShrinkToUsedDataArea( bool& o_bShrunk, SCTAB nTab, SCCOL& rStar
     return maTabs[nTab]->ShrinkToUsedDataArea( o_bShrunk, rStartCol, rStartRow, rEndCol, rEndRow, bColumnsOnly);
 }
 
-SCROW ScDocument::GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2 ) const
+SCROW ScDocument::GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nLastRow ) const
 {
     const ScTable* pTab = FetchTable(nTab);
     if (!pTab)
         return -1;
 
-    return pTab->GetLastDataRow(nCol1, nCol2);
+    return pTab->GetLastDataRow(nCol1, nCol2, nLastRow);
 }
 
 // connected area
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index b659409..249e442 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3365,7 +3365,8 @@ class GroupTokenConverter
 
     SCROW trimLength(SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCROW nRowLen)
     {
-        SCROW nLastRow = mrDoc.GetLastDataRow(nTab, nCol1, nCol2);
+        SCROW nLastRow = nRow + nRowLen - 1; // current last row.
+        nLastRow = mrDoc.GetLastDataRow(nTab, nCol1, nCol2, nLastRow);
         if (nLastRow < (nRow + nRowLen - 1))
             nRowLen = nLastRow - nRow + 1;
         else if (nLastRow == 0)
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 9af12d6..f827cc9 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -987,20 +987,20 @@ bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rS
             (rStartRow != rEndRow || aCol[rStartCol].HasDataAt( rStartRow)));
 }
 
-SCROW ScTable::GetLastDataRow( SCCOL nCol1, SCCOL nCol2 ) const
+SCROW ScTable::GetLastDataRow( SCCOL nCol1, SCCOL nCol2, SCROW nLastRow ) const
 {
     if (!ValidCol(nCol1) || !ValidCol(nCol2))
         return -1;
 
-    SCROW nLastRow = 0;
+    SCROW nNewLastRow = 0;
     for (SCCOL i = nCol1; i <= nCol2; ++i)
     {
-        SCROW nThis = aCol[i].GetLastDataPos();
-        if (nLastRow < nThis)
-            nLastRow = nThis;
+        SCROW nThis = aCol[i].GetLastDataPos(nLastRow);
+        if (nNewLastRow < nThis)
+            nNewLastRow = nThis;
     }
 
-    return nLastRow;
+    return nNewLastRow;
 }
 
 SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
commit de746be2078c191692d94d11006564ec60090b7d
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Sep 10 09:17:12 2013 -0400

    Oops I forgot a return statement.
    
    Change-Id: Ifdea804b178ccf5c25ef21fba2642f31a90e4061

diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index d161910..7bda1da 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1024,7 +1024,7 @@ SCROW ScDocument::GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2 ) const
     if (!pTab)
         return -1;
 
-    pTab->GetLastDataRow(nCol1, nCol2);
+    return pTab->GetLastDataRow(nCol1, nCol2);
 }
 
 // connected area
commit d466bd65be615516ee5402915abb26e4f3775e23
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Tue Sep 10 00:11:13 2013 -0400

    Fix several logic errors in required array size calculation.
    
    Change-Id: Ife05e21583d14c873d38c09d78e964cdb3817d6c

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index be9fd90..b659409 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3440,7 +3440,7 @@ public:
                 case svDoubleRef:
                 {
                     ScComplexRefData aRef = pToken->GetDoubleRef();
-                    ScRange aAbs = aRef.toAbs(mrCell.aPos);
+                    ScRange aAbs = aRef.toAbs(mrPos);
 
                     // Check for self reference.
                     if (aRef.Ref1.IsRowRel())
@@ -3466,12 +3466,16 @@ public:
                     size_t nCols = aAbs.aEnd.Col() - aAbs.aStart.Col() + 1;
                     std::vector<formula::VectorRefArray> aArrays;
                     aArrays.reserve(nCols);
-                    SCROW nArrayLength = nLen;
                     SCROW nRefRowSize = aAbs.aEnd.Row() - aAbs.aStart.Row() + 1;
+                    SCROW nArrayLength = nRefRowSize;
                     if (!bAbsLast)
                     {
                         // range end position is relative. Extend the array length.
-                        nArrayLength += nRefRowSize - 1;
+                        SCROW nLastRefRowOffset = aAbs.aEnd.Row() - mrPos.Row();
+                        SCROW nLastRefRow = mrPos.Row() + nLen - 1 + nLastRefRowOffset;
+                        SCROW nNewLength = nLastRefRow - aAbs.aStart.Row() + 1;
+                        if (nNewLength > nArrayLength)
+                            nArrayLength = nNewLength;
                     }
 
                     // Trim trailing empty rows.
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 5dff3d9..1dbe5bd 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -204,9 +204,14 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
                         nRowEnd += i;
                     size_t nRowSize = nRowEnd - nRowStart + 1;
                     ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize));
-                    if (p2->GetArrayLength() < nRowSize)
-                        // Data array is shorter than the row size of the reference. Truncate it.
-                        nRowSize = p2->GetArrayLength();
+
+                    size_t nDataRowEnd = p2->GetArrayLength() - 1;
+                    if (nRowStart > nDataRowEnd)
+                        // Referenced rows are all empty.
+                        nRowSize = 0;
+                    else if (nRowEnd > nDataRowEnd)
+                        // Data array is shorter than the row size of the reference. Truncate it to the data.
+                        nRowSize -= nRowEnd - nDataRowEnd;
 
                     for (size_t nCol = 0; nCol < nColSize; ++nCol)
                     {
commit ae0d98e18125ecd3fa92f4612a62da32c704579d
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Sep 9 23:14:19 2013 -0400

    Trim data array length to remove trailing empty rows.
    
    Change-Id: I61a6a289ad1c2c757fcea490ada5d40fee08e840

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 6949b6d..4cbf06a 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1027,6 +1027,13 @@ public:
                                           SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
                                           SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const;
 
+    /**
+     * Return the last non-empty row position in given columns, or 0 if the
+     * columns are empty. A negative value is returned if the given sheet or
+     * column positions are invalid.
+     */
+    SCROW GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2 ) const;
+
     SC_DLLPUBLIC void           GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
                                     SCCOL& rEndCol, SCROW& rEndRow, bool bIncludeOld, bool bOnlyDown ) const;
     SC_DLLPUBLIC bool           GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const;
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 8816642..9bf3f90 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -469,6 +469,8 @@ public:
     bool        ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rStartRow,
                                       SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const;
 
+    SCROW GetLastDataRow( SCCOL nCol1, SCCOL nCol2 ) const;
+
     SCSIZE      GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
                                         SCCOL nEndCol, SCROW nEndRow, ScDirection eDir ) const;
 
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index c6d3c79..d161910 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1018,6 +1018,15 @@ bool ScDocument::ShrinkToUsedDataArea( bool& o_bShrunk, SCTAB nTab, SCCOL& rStar
     return maTabs[nTab]->ShrinkToUsedDataArea( o_bShrunk, rStartCol, rStartRow, rEndCol, rEndRow, bColumnsOnly);
 }
 
+SCROW ScDocument::GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2 ) const
+{
+    const ScTable* pTab = FetchTable(nTab);
+    if (!pTab)
+        return -1;
+
+    pTab->GetLastDataRow(nCol1, nCol2);
+}
+
 // connected area
 
 void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 87a3d05..be9fd90 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3362,6 +3362,18 @@ class GroupTokenConverter
 
         return true;
     }
+
+    SCROW trimLength(SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCROW nRowLen)
+    {
+        SCROW nLastRow = mrDoc.GetLastDataRow(nTab, nCol1, nCol2);
+        if (nLastRow < (nRow + nRowLen - 1))
+            nRowLen = nLastRow - nRow + 1;
+        else if (nLastRow == 0)
+            // Column is empty.
+            nRowLen = 1;
+
+        return nRowLen;
+    }
 public:
     GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) :
         mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos) {}
@@ -3397,6 +3409,9 @@ public:
                         if (isSelfReferenceRelative(aRefPos, aRef.Row()))
                             return false;
 
+                        // Trim data array length to actual data range.
+                        nLen = trimLength(aRefPos.Tab(), aRefPos.Col(), aRefPos.Col(), aRefPos.Row(), nLen);
+
                         // Fetch double array guarantees that the length of the
                         // returned array equals or greater than the requested
                         // length.
@@ -3459,6 +3474,9 @@ public:
                         nArrayLength += nRefRowSize - 1;
                     }
 
+                    // Trim trailing empty rows.
+                    nArrayLength = trimLength(aRefPos.Tab(), aAbs.aStart.Col(), aAbs.aEnd.Col(), aRefPos.Row(), nArrayLength);
+
                     for (SCCOL i = aAbs.aStart.Col(); i <= aAbs.aEnd.Col(); ++i)
                     {
                         aRefPos.SetCol(i);
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 6391eee..9af12d6 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -987,6 +987,21 @@ bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rS
             (rStartRow != rEndRow || aCol[rStartCol].HasDataAt( rStartRow)));
 }
 
+SCROW ScTable::GetLastDataRow( SCCOL nCol1, SCCOL nCol2 ) const
+{
+    if (!ValidCol(nCol1) || !ValidCol(nCol2))
+        return -1;
+
+    SCROW nLastRow = 0;
+    for (SCCOL i = nCol1; i <= nCol2; ++i)
+    {
+        SCROW nThis = aCol[i].GetLastDataPos();
+        if (nLastRow < nThis)
+            nLastRow = nThis;
+    }
+
+    return nLastRow;
+}
 
 SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
                                         SCCOL nEndCol, SCROW nEndRow, ScDirection eDir ) const
commit 71958acc9c6650606e59321b9b9aaf8c11ef907f
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Sep 9 20:39:17 2013 -0400

    Eliminate (almost) duplicate code blocks.
    
    Change-Id: Ib5d0fae3efda6bde056f7e4990de57c8b3541549

diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 048402f..42c5469 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2050,6 +2050,26 @@ void ScColumn::FillMatrix( ScMatrix& rMat, size_t nMatCol, SCROW nRow1, SCROW nR
 
 namespace {
 
+template<typename _Blk>
+void getBlockIterators(
+    sc::CellStoreType::iterator it, size_t& rLenRemain,
+    typename _Blk::iterator& rData, typename _Blk::iterator& rDataEnd )
+{
+    rData = _Blk::begin(*it->data);
+    if (rLenRemain >= it->size)
+    {
+        // Block is shorter than the remaining requested length.
+        rDataEnd = _Blk::end(*it->data);
+        rLenRemain -= it->size;
+    }
+    else
+    {
+        rDataEnd = rData;
+        std::advance(rDataEnd, rLenRemain);
+        rLenRemain = 0;
+    }
+}
+
 bool appendDouble(
     sc::FormulaGroupContext::NumArrayType& rArray, size_t nLen,
     sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd )
@@ -2064,20 +2084,8 @@ bool appendDouble(
         {
             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;
-                }
+                sc::numeric_block::iterator itData, itDataEnd;
+                getBlockIterators<sc::numeric_block>(it, nLenRemain, itData, itDataEnd);
 
                 for (; itData != itDataEnd; ++itData)
                     rArray.push_back(*itData);
@@ -2085,20 +2093,8 @@ bool appendDouble(
             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;
-                }
+                sc::formula_block::iterator itData, itDataEnd;
+                getBlockIterators<sc::formula_block>(it, nLenRemain, itData, itDataEnd);
 
                 sal_uInt16 nErr;
                 double fVal;
@@ -2161,20 +2157,8 @@ bool appendStrings(
         {
             case sc::element_type_string:
             {
-                sc::string_block::iterator itData = sc::string_block::begin(*it->data);
-                sc::string_block::iterator itDataEnd;
-                if (nLenRemain >= it->size)
-                {
-                    // Block is shorter than the remaining requested length.
-                    itDataEnd = sc::string_block::end(*it->data);
-                    nLenRemain -= it->size;
-                }
-                else
-                {
-                    itDataEnd = itData;
-                    std::advance(itDataEnd, nLenRemain);
-                    nLenRemain = 0;
-                }
+                sc::string_block::iterator itData, itDataEnd;
+                getBlockIterators<sc::string_block>(it, nLenRemain, itData, itDataEnd);
 
                 for (; itData != itDataEnd; ++itData)
                     rArray.push_back(rCxt.intern(*itData));
@@ -2182,20 +2166,8 @@ bool appendStrings(
             break;
             case sc::element_type_edittext:
             {
-                sc::edittext_block::iterator itData = sc::edittext_block::begin(*it->data);
-                sc::edittext_block::iterator itDataEnd;
-                if (nLenRemain >= it->size)
-                {
-                    // Block is shorter than the remaining requested length.
-                    itDataEnd = sc::edittext_block::end(*it->data);
-                    nLenRemain -= it->size;
-                }
-                else
-                {
-                    itDataEnd = itData;
-                    std::advance(itDataEnd, nLenRemain);
-                    nLenRemain = 0;
-                }
+                sc::edittext_block::iterator itData, itDataEnd;
+                getBlockIterators<sc::edittext_block>(it, nLenRemain, itData, itDataEnd);
 
                 for (; itData != itDataEnd; ++itData)
                 {
@@ -2206,20 +2178,8 @@ bool appendStrings(
             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;
-                }
+                sc::formula_block::iterator itData, itDataEnd;
+                getBlockIterators<sc::formula_block>(it, nLenRemain, itData, itDataEnd);
 
                 sal_uInt16 nErr;
                 OUString aStr;
commit b951445113add8360a3efb97091faefb3c870ce5
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Sep 9 19:36:30 2013 -0400

    Support fetching string array that spans over multiple blocks.
    
    Change-Id: I543fca231e0be886159b8ddbd83ceffa1bf69c1b

diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 835eb91..a494759 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -252,6 +252,7 @@ public:
     sal_uInt16      GetErrCode();   // interpret first if necessary
     sal_uInt16      GetRawError();  // don't interpret, just return code or result error
     bool GetErrorOrValue( sal_uInt16& rErr, double& rVal );
+    bool GetErrorOrString( sal_uInt16& rErr, OUString& rStr );
     sal_uInt8       GetMatrixFlag() const;
     ScTokenArray* GetCode();
     const ScTokenArray* GetCode() const;
diff --git a/sc/inc/formularesult.hxx b/sc/inc/formularesult.hxx
index 00cc9fd..4f13524 100644
--- a/sc/inc/formularesult.hxx
+++ b/sc/inc/formularesult.hxx
@@ -135,6 +135,7 @@ public:
     bool IsMultiline() const;
 
     bool GetErrorOrDouble( sal_uInt16& rErr, double& rVal ) const;
+    bool GetErrorOrString( sal_uInt16& rErr, OUString& rStr ) const;
 
     /** Get error code if set or GetCellResultType() is formula::svError or svUnknown,
         else 0. */
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 7a97972..048402f 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2148,6 +2148,138 @@ bool appendDouble(
     return false;
 }
 
+bool appendStrings(
+    sc::FormulaGroupContext& rCxt, ScDocument* pDoc,
+    sc::FormulaGroupContext::StrArrayType& rArray, size_t nLen,
+    sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd )
+{
+    size_t nLenRemain = nLen;
+
+    for (; it != itEnd; ++it)
+    {
+        switch (it->type)
+        {
+            case sc::element_type_string:
+            {
+                sc::string_block::iterator itData = sc::string_block::begin(*it->data);
+                sc::string_block::iterator itDataEnd;
+                if (nLenRemain >= it->size)
+                {
+                    // Block is shorter than the remaining requested length.
+                    itDataEnd = sc::string_block::end(*it->data);
+                    nLenRemain -= it->size;
+                }
+                else
+                {
+                    itDataEnd = itData;
+                    std::advance(itDataEnd, nLenRemain);
+                    nLenRemain = 0;
+                }
+
+                for (; itData != itDataEnd; ++itData)
+                    rArray.push_back(rCxt.intern(*itData));
+            }
+            break;
+            case sc::element_type_edittext:
+            {
+                sc::edittext_block::iterator itData = sc::edittext_block::begin(*it->data);
+                sc::edittext_block::iterator itDataEnd;
+                if (nLenRemain >= it->size)
+                {
+                    // Block is shorter than the remaining requested length.
+                    itDataEnd = sc::edittext_block::end(*it->data);
+                    nLenRemain -= it->size;
+                }
+                else
+                {
+                    itDataEnd = itData;
+                    std::advance(itDataEnd, nLenRemain);
+                    nLenRemain = 0;
+                }
+
+                for (; itData != itDataEnd; ++itData)
+                {
+                    OUString aStr = ScEditUtil::GetString(**itData, pDoc);
+                    rArray.push_back(rCxt.intern(aStr));
+                }
+            }
+            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;
+                }
+
+                sal_uInt16 nErr;
+                OUString aStr;
+                for (; itData != itDataEnd; ++itData)
+                {
+                    ScFormulaCell& rFC = **itData;
+                    if (!rFC.GetErrorOrString(nErr, aStr) || nErr)
+                    {
+                        if (nErr == ScErrorCodes::errCircularReference)
+                        {
+                            // This cell needs to be recalculated on next visit.
+                            rFC.SetErrCode(0);
+                            rFC.SetDirtyVar();
+                        }
+                        return false;
+                    }
+
+                    rArray.push_back(rCxt.intern(aStr));
+                }
+            }
+            break;
+            case sc::element_type_empty:
+            {
+                // Fill it with NULL pointers.
+                if (nLenRemain >= it->size)
+                {
+                    rArray.resize(rArray.size() + it->size, NULL);
+                    nLenRemain -= it->size;
+                }
+                else
+                {
+                    rArray.resize(rArray.size() + nLenRemain, NULL);
+                    nLenRemain = 0;
+                }
+            }
+            break;
+            case sc::element_type_numeric:
+            default:
+                return false;
+        }
+
+        if (!nLenRemain)
+            return true;
+    }
+
+    return false;
+}
+
+void copyFirstBlock( sc::FormulaGroupContext& rCxt, size_t nLen, const sc::CellStoreType::position_type& rPos )
+{
+    rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType);
+    sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back();
+    rArray.reserve(nLen);
+
+    const OUString* p = &sc::string_block::at(*rPos.first->data, rPos.second);
+    const OUString* pEnd = p + nLen;
+    for (; p != pEnd; ++p)
+        rArray.push_back(rCxt.intern(*p));
+}
+
 }
 
 formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext& rCxt, SCROW nRow1, SCROW nRow2 )
@@ -2256,20 +2388,20 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext&
             if (nLenRequested <= nLen)
             {
                 // Requested length fits a single block.
-                rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType);
+                copyFirstBlock(rCxt, nLenRequested, aPos);
                 sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back();
-                rArray.reserve(nLenRequested);
-
-                const OUString* p = &sc::string_block::at(*aPos.first->data, aPos.second);
-                const OUString* pEnd = p + nLenRequested;
-                for (; p != pEnd; ++p)
-                    rArray.push_back(rCxt.intern(*p));
-
                 return formula::VectorRefArray(&rArray[0]);
             }
 
-            // TODO: handle cases where the requested length goes beyond the
-            // current block just like we do with numeric array.
+            copyFirstBlock(rCxt, nLen, aPos);
+            sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back();
+
+            // Fill the remaining array with values from the following blocks.
+            ++aPos.first;
+            if (!appendStrings(rCxt, pDocument, rArray, nLenRequested - nLen, aPos.first, maCells.end()))
+                return formula::VectorRefArray();
+
+            return formula::VectorRefArray(&rArray[0]);
         }
         break;
         case sc::element_type_empty:
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 0f248a2..87a3d05 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2082,6 +2082,17 @@ bool ScFormulaCell::GetErrorOrValue( sal_uInt16& rErr, double& rVal )
     return aResult.GetErrorOrDouble(rErr, rVal);
 }
 
+bool ScFormulaCell::GetErrorOrString( sal_uInt16& rErr, OUString& rStr )
+{
+    MaybeInterpret();
+
+    rErr = pCode->GetCodeError();
+    if (rErr)
+        return true;
+
+    return aResult.GetErrorOrString(rErr, rStr);
+}
+
 bool ScFormulaCell::HasOneReference( ScRange& r ) const
 {
     pCode->Reset();
diff --git a/sc/source/core/tool/formularesult.cxx b/sc/source/core/tool/formularesult.cxx
index 511bfa5..ef6c15a 100644
--- a/sc/source/core/tool/formularesult.cxx
+++ b/sc/source/core/tool/formularesult.cxx
@@ -255,6 +255,19 @@ inline bool isValue( formula::StackVar sv )
         || sv == formula::svEmptyCell || sv == formula::svHybridValueCell;
 }
 
+inline bool isString( formula::StackVar sv )
+{
+    switch (sv)
+    {
+        case formula::svString:
+        case formula::svHybridCell:
+        case formula::svHybridValueCell:
+            return true;
+    }
+
+    return false;
+}
+
 }
 
 bool ScFormulaResult::IsValue() const
@@ -321,6 +334,42 @@ bool ScFormulaResult::GetErrorOrDouble( sal_uInt16& rErr, double& rVal ) const
     return true;
 }
 
+bool ScFormulaResult::GetErrorOrString( sal_uInt16& rErr, OUString& rStr ) const
+{
+    if (mnError)
+    {
+        rErr = mnError;
+        return true;
+    }
+
+    formula::StackVar sv = GetCellResultType();
+    if (sv == formula::svError)
+    {
+        if (GetType() == formula::svMatrixCell)
+        {
+            // don't need to test for mpToken here, GetType() already did it
+            rErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
+                GetUpperLeftToken()->GetError();
+        }
+        else if (mpToken)
+        {
+            rErr = mpToken->GetError();
+        }
+    }
+
+    if (rErr)
+        return true;
+
+    if (!mbToken)
+        return false;
+
+    if (!isString(sv))
+        return false;
+
+    rStr = GetString();
+    return true;
+}
+
 sal_uInt16 ScFormulaResult::GetResultError() const
 {
     if (mnError)
commit f8fe9f0f25787b9d73ec417dd06118e6a72b9631
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Sep 9 18:53:33 2013 -0400

    Move common code blocks to a function.
    
    Change-Id: I1b1aaa0b1dd8cc6e14fbac1981c67a8b63c92c2c

diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 0b37b97..5dff3d9 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -83,6 +83,18 @@ void fillMatrix( ScMatrix& rMat, size_t nCol, const double* pNums, size_t nLen )
     }
 }
 
+void flushSegment(
+    ScMatrix& rMat, size_t nCol, rtl_uString** pHead, rtl_uString** pCur, rtl_uString** pTop )
+{
+    size_t nOffset = pHead - pTop;
+    std::vector<OUString> aStrs;
+    aStrs.reserve(pCur - pHead);
+    for (; pHead != pCur; ++pHead)
+        aStrs.push_back(OUString(*pHead));
+
+    rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset);
+}
+
 void fillMatrix( ScMatrix& rMat, size_t nCol, rtl_uString** pStrs, size_t nLen )
 {
     rtl_uString** p = pStrs;
@@ -102,13 +114,7 @@ void fillMatrix( ScMatrix& rMat, size_t nCol, rtl_uString** pStrs, size_t nLen )
         if (pHead)
         {
             // Flush this non-empty segment to the matrix.
-            size_t nOffset = pHead - pStrs;
-            std::vector<OUString> aStrs;
-            aStrs.reserve(p - pHead);
-            for (; pHead != p; ++pHead)
-                aStrs.push_back(OUString(*pHead));
-
-            rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset);
+            flushSegment(rMat, nCol, pHead, p, pStrs);
             pHead = NULL;
         }
     }
@@ -116,13 +122,7 @@ void fillMatrix( ScMatrix& rMat, size_t nCol, rtl_uString** pStrs, size_t nLen )
     if (pHead)
     {
         // Flush last non-empty segment to the matrix.
-        size_t nOffset = pHead - pStrs;
-        std::vector<OUString> aStrs;
-        aStrs.reserve(p - pHead);
-        for (; pHead != p; ++pHead)
-            aStrs.push_back(OUString(*pHead));
-
-        rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset);
+        flushSegment(rMat, nCol, pHead, p, pStrs);
     }
 }
 
commit 7d0f3695a20df18f5f6e609f70b8d1ef7825302b
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Sep 9 18:00:08 2013 -0400

    Correctly handle empty cells for string arrays too.
    
    Because we need to make a distinction between an empty cell and a string
    cell containing zero-length string, I decided to switch to using
    rtl_uString* array and use NULL values as empty cells.
    
    Change-Id: I5bedb593507f34782e41a8a900602d445e5b1f6f

diff --git a/formula/source/core/api/vectortoken.cxx b/formula/source/core/api/vectortoken.cxx
index 557e0c0..b752f5d 100644
--- a/formula/source/core/api/vectortoken.cxx
+++ b/formula/source/core/api/vectortoken.cxx
@@ -13,7 +13,7 @@ namespace formula {
 
 VectorRefArray::VectorRefArray() : mpNumericArray(NULL), mbNumeric(true) {}
 VectorRefArray::VectorRefArray( const double* pArray ) : mpNumericArray(pArray), mbNumeric(true) {}
-VectorRefArray::VectorRefArray( const OUString* pArray ) : mpStringArray(pArray), mbNumeric(false) {}
+VectorRefArray::VectorRefArray( rtl_uString** pArray ) : mpStringArray(pArray), mbNumeric(false) {}
 
 SingleVectorRefToken::SingleVectorRefToken( const double* pArray, size_t nLength ) :
     FormulaToken(svSingleVectorRef, ocPush), maArray(pArray), mnArrayLength(nLength) {}
diff --git a/include/formula/vectortoken.hxx b/include/formula/vectortoken.hxx
index 5186ca5..9bc82f3 100644
--- a/include/formula/vectortoken.hxx
+++ b/include/formula/vectortoken.hxx
@@ -18,14 +18,14 @@ struct FORMULA_DLLPUBLIC VectorRefArray
 {
     union {
         const double* mpNumericArray;
-        const OUString* mpStringArray;
+        rtl_uString** mpStringArray;
     };
 
     bool mbNumeric;
 
     VectorRefArray();
     VectorRefArray( const double* pArray );
-    VectorRefArray( const OUString* pArray );
+    VectorRefArray( rtl_uString** pArray );
 };
 
 /**
diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
index 776b24d..f57b237 100644
--- a/sc/inc/formulagroup.hxx
+++ b/sc/inc/formulagroup.hxx
@@ -15,6 +15,7 @@
 
 #include <boost/noncopyable.hpp>
 #include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/unordered_set.hpp>
 
 class ScDocument;
 class ScTokenArray;
@@ -23,13 +24,17 @@ namespace sc {
 
 struct FormulaGroupContext : boost::noncopyable
 {
+    typedef boost::unordered_set<OUString, OUStringHash> StrHashType;
     typedef std::vector<double> NumArrayType;
-    typedef std::vector<OUString> StrArrayType;
+    typedef std::vector<rtl_uString*> StrArrayType;
     typedef boost::ptr_vector<NumArrayType> NumArrayStoreType;
     typedef boost::ptr_vector<StrArrayType> StrArrayStoreType;
 
+    StrHashType maStrPool;
     NumArrayStoreType maNumArrays;
     StrArrayStoreType maStrArrays;
+
+    rtl_uString* intern( const OUString& rStr );
 };
 
 /**
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 34ecbb2..7a97972 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2256,8 +2256,16 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext&
             if (nLenRequested <= nLen)
             {
                 // Requested length fits a single block.
+                rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType);
+                sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back();
+                rArray.reserve(nLenRequested);
+
                 const OUString* p = &sc::string_block::at(*aPos.first->data, aPos.second);
-                return formula::VectorRefArray(p);
+                const OUString* pEnd = p + nLenRequested;
+                for (; p != pEnd; ++p)
+                    rArray.push_back(rCxt.intern(*p));
+
+                return formula::VectorRefArray(&rArray[0]);
             }
 
             // TODO: handle cases where the requested length goes beyond the
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index f6a1dff..0b37b97 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -29,6 +29,23 @@
 
 namespace sc {
 
+rtl_uString* FormulaGroupContext::intern( const OUString& rStr )
+{
+    StrHashType::iterator it = maStrPool.find(rStr);
+    if (it == maStrPool.end())
+    {
+        // Not yet in the pool.
+        std::pair<StrHashType::iterator, bool> r = maStrPool.insert(rStr.intern());
+        if (!r.second)
+            // Insertion failed.
+            return NULL;
+
+        it = r.first;
+    }
+
+    return it->pData;
+}
+
 namespace {
 
 /**
@@ -63,7 +80,49 @@ void fillMatrix( ScMatrix& rMat, size_t nCol, const double* pNums, size_t nLen )
     {
         // Flush last non-NaN segment to the matrix.
         rMat.PutDouble(pHead, p - pHead, nCol, pHead - pNums);
-        pHead = NULL;
+    }
+}
+
+void fillMatrix( ScMatrix& rMat, size_t nCol, rtl_uString** pStrs, size_t nLen )
+{
+    rtl_uString** p = pStrs;
+    rtl_uString** pEnd = p + nLen;
+    rtl_uString** pHead = NULL;
+    for (; p != pEnd; ++p)
+    {
+        if (*p)
+        {
+            if (!pHead)
+                // Store the first non-empty string position.
+                pHead = p;
+
+            continue;
+        }
+
+        if (pHead)
+        {
+            // Flush this non-empty segment to the matrix.
+            size_t nOffset = pHead - pStrs;
+            std::vector<OUString> aStrs;
+            aStrs.reserve(p - pHead);
+            for (; pHead != p; ++pHead)
+                aStrs.push_back(OUString(*pHead));
+
+            rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset);
+            pHead = NULL;
+        }
+    }
+
+    if (pHead)
+    {
+        // Flush last non-empty segment to the matrix.
+        size_t nOffset = pHead - pStrs;
+        std::vector<OUString> aStrs;
+        aStrs.reserve(p - pHead);
+        for (; pHead != p; ++pHead)
+            aStrs.push_back(OUString(*pHead));
+
+        rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset);
     }
 }
 
@@ -124,7 +183,14 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
                             aCode2.AddDouble(fVal);
                     }
                     else
-                        aCode2.AddString(static_cast<size_t>(i) < p2->GetArrayLength() ? rArray.mpStringArray[i] : OUString());
+                    {
+                        rtl_uString* pStr = NULL;
+                        if (static_cast<size_t>(i) < p2->GetArrayLength())
+                            pStr = rArray.mpStringArray[i];
+
+                        if (pStr)
+                            aCode2.AddString(OUString(pStr));
+                    }
                 }
                 break;
                 case formula::svDoubleVectorRef:
@@ -138,6 +204,10 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
                         nRowEnd += i;
                     size_t nRowSize = nRowEnd - nRowStart + 1;
                     ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize));
+                    if (p2->GetArrayLength() < nRowSize)
+                        // Data array is shorter than the row size of the reference. Truncate it.
+                        nRowSize = p2->GetArrayLength();
+
                     for (size_t nCol = 0; nCol < nColSize; ++nCol)
                     {
                         const formula::VectorRefArray& rArray = rArrays[nCol];
@@ -149,9 +219,9 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
                         }
                         else
                         {
-                            const OUString* pStrs = rArray.mpStringArray;
+                            rtl_uString** pStrs = rArray.mpStringArray;
                             pStrs += nRowStart;
-                            pMat->PutString(pStrs, nRowSize, nCol, 0);
+                            fillMatrix(*pMat, nCol, pStrs, nRowSize);
                         }
                     }
 
commit 6dd0d051e986b868bf2225c16137e72d6e2dd3b6
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Sep 9 15:32:25 2013 -0400

    Do the same for range vector tokens.
    
    Change-Id: Id80f76dbe575fc6b279dafbfc524a9230755ddc8

diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 5f7f843..34ecbb2 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2268,8 +2268,10 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext&
         {
             if (nLenRequested <= nLen)
             {
-                // Fill the whole length with zero.
-                rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(nLenRequested, 0.0));
+                // Fill the whole length with NaN's.
+                double fNan;
+                rtl::math::setNan(&fNan);
+                rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(nLenRequested, fNan));
                 return formula::VectorRefArray(&rCxt.maNumArrays.back()[0]);
             }
 
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index ca888dc..f6a1dff 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -29,6 +29,46 @@
 
 namespace sc {
 
+namespace {
+
+/**
+ * Input double array consists of segments of NaN's and normal values.
+ * Insert only the normal values into the matrix while skipping the NaN's.
+ */
+void fillMatrix( ScMatrix& rMat, size_t nCol, const double* pNums, size_t nLen )
+{
+    const double* p = pNums;
+    const double* pEnd = p + nLen;
+    const double* pHead = NULL;
+    for (; p != pEnd; ++p)
+    {
+        if (!rtl::math::isNan(*p))
+        {
+            if (!pHead)
+                // Store the first non-NaN position.
+                pHead = p;
+
+            continue;
+        }
+
+        if (pHead)
+        {
+            // Flush this non-NaN segment to the matrix.
+            rMat.PutDouble(pHead, p - pHead, nCol, pHead - pNums);
+            pHead = NULL;
+        }
+    }
+
+    if (pHead)
+    {
+        // Flush last non-NaN segment to the matrix.
+        rMat.PutDouble(pHead, p - pHead, nCol, pHead - pNums);
+        pHead = NULL;
+    }
+}
+
+}
+
 ScMatrixRef FormulaGroupInterpreterSoftware::inverseMatrix(const ScMatrix& /*rMat*/)
 {
     return ScMatrixRef();
@@ -97,7 +137,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
                     if (!p2->IsEndFixed())
                         nRowEnd += i;
                     size_t nRowSize = nRowEnd - nRowStart + 1;
-                    ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize, 0.0));
+                    ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize));
                     for (size_t nCol = 0; nCol < nColSize; ++nCol)
                     {
                         const formula::VectorRefArray& rArray = rArrays[nCol];
@@ -105,7 +145,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
                         {
                             const double* pNums = rArray.mpNumericArray;
                             pNums += nRowStart;
-                            pMat->PutDouble(pNums, nRowSize, nCol, 0);
+                            fillMatrix(*pMat, nCol, pNums, nRowSize);
                         }
                         else
                         {
commit d1c90e929ef765b0d88a8d1e0bda434a1e340bee
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Sep 9 14:24:10 2013 -0400

    Correctly handle empty cells in group calculation (software interpreter).
    
    Store NaN's to represent empty cells rather than storing 0's. Storing 0's
    would mess up COUNT(), for example.
    
    Change-Id: I8e350e1fe31358b844dd44451ed8659172fda1cb

diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 9d0130c..5f7f843 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2055,6 +2055,9 @@ bool appendDouble(
     sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd )
 {
     size_t nLenRemain = nLen;
+    double fNan;
+    rtl::math::setNan(&fNan);
+
     for (; it != itEnd; ++it)
     {
         switch (it->type)
@@ -2119,15 +2122,15 @@ bool appendDouble(
             break;
             case sc::element_type_empty:
             {
-                // Fill it with 0's.
+                // Fill it with NaN's.
                 if (nLenRemain >= it->size)
                 {
-                    rArray.resize(rArray.size() + it->size, 0);
+                    rArray.resize(rArray.size() + it->size, fNan);
                     nLenRemain -= it->size;
                 }
                 else
                 {
-                    rArray.resize(rArray.size() + nLenRemain, 0);
+                    rArray.resize(rArray.size() + nLenRemain, fNan);
                     nLenRemain = 0;
                 }
             }
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 6c930e5..ca888dc 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -50,6 +50,9 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
     aResults.reserve(xGroup->mnLength);
     CachedTokensType aCachedTokens;
 
+    double fNan;
+    rtl::math::setNan(&fNan);
+
     for (SCROW i = 0; i < xGroup->mnLength; ++i, aTmpPos.IncRow())
     {
         ScTokenArray aCode2;
@@ -70,7 +73,16 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
                     const formula::SingleVectorRefToken* p2 = static_cast<const formula::SingleVectorRefToken*>(p);
                     const formula::VectorRefArray& rArray = p2->GetArray();
                     if (rArray.mbNumeric)
-                        aCode2.AddDouble(static_cast<size_t>(i) < p2->GetArrayLength() ? rArray.mpNumericArray[i] : 0.0);
+                    {
+                        double fVal = fNan;
+                        if (static_cast<size_t>(i) < p2->GetArrayLength())
+                            fVal = rArray.mpNumericArray[i];
+
+                        if (rtl::math::isNan(fVal))
+                            aCode2.AddToken(ScEmptyCellToken(false, false));
+                        else
+                            aCode2.AddDouble(fVal);
+                    }
                     else
                         aCode2.AddString(static_cast<size_t>(i) < p2->GetArrayLength() ? rArray.mpStringArray[i] : OUString());
                 }
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index 4dbbf1d..470c8d8 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -880,7 +880,7 @@ void ScInterpreter::ScCount()
 
     while (nParamCount-- > 0)
     {
-        switch (GetStackType())
+        switch (GetRawStackType())
         {
             case svString:
             {
commit 2e5111f58994d6449fd03b1fc2c4971da78deded
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Sep 9 11:05:03 2013 -0400

    The OpenCL interpreter doesn't have to be a child class of the S/W one.
    
    Change-Id: Idcc28b98fceaffdc8947410fef5fadbae462450b

diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
index 0f8b46f..279ac2d 100644
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -104,7 +104,7 @@ public:
 
 };
 
-class FormulaGroupInterpreterOpenCL : public FormulaGroupInterpreterSoftware
+class FormulaGroupInterpreterOpenCL : public FormulaGroupInterpreter
 {
     SourceData *mSrcDataStack[SRCDATASIZE];
     unsigned int mnStackPointer,mnDoublePtrCount;
@@ -124,7 +124,7 @@ class FormulaGroupInterpreterOpenCL : public FormulaGroupInterpreterSoftware
     size_t mnRowSize;
 public:
     FormulaGroupInterpreterOpenCL() :
-        FormulaGroupInterpreterSoftware()
+        FormulaGroupInterpreter()
     {
         mnStackPointer = 0;
         mnpOclEndPos = NULL;
@@ -952,6 +952,9 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, const ScAddress
 /// Special case of formula compiler for groundwatering
 class FormulaGroupInterpreterGroundwater : public FormulaGroupInterpreterSoftware
 {
+    bool interpretCL(ScDocument& rDoc, const ScAddress& rTopPos,
+                     const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode);
+
 public:
     FormulaGroupInterpreterGroundwater() :
         FormulaGroupInterpreterSoftware()
@@ -965,8 +968,6 @@ public:
     }
 
     virtual ScMatrixRef inverseMatrix(const ScMatrix& /* rMat */) { return ScMatrixRef(); }
-    virtual bool interpretCL(ScDocument& rDoc, const ScAddress& rTopPos,
-                             const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode);
     virtual bool interpret(ScDocument& rDoc, const ScAddress& rTopPos,
                            const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode);
 };
commit f4d04f2014cedacdba3eec2177a3ba4acd3d6b6f
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Sep 9 10:52:42 2013 -0400

    Instantiate the software fallback outside of opencl code.
    
    Change-Id: I7ec7a951492616abd3c7327b85f09c1e913208ca

diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
index 0ae58e8..0f8b46f 100644
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -1063,18 +1063,18 @@ bool FormulaGroupInterpreterGroundwater::interpret(ScDocument& rDoc, const ScAdd
 }
 
 namespace opencl {
-    sc::FormulaGroupInterpreter *createFormulaGroupInterpreter()
-    {
-        if (getenv("SC_SOFTWARE"))
-        {
-            fprintf(stderr, "Create S/W interp\n");
-            return new sc::FormulaGroupInterpreterSoftware();
-        }
-        if (getenv("SC_GROUNDWATER"))
-            return new sc::FormulaGroupInterpreterGroundwater();
-        else
-            return new sc::FormulaGroupInterpreterOpenCL();
-    }
+
+sc::FormulaGroupInterpreter *createFormulaGroupInterpreter()
+{
+    if (getenv("SC_SOFTWARE"))
+        return NULL;
+
+    if (getenv("SC_GROUNDWATER"))
+        return new sc::FormulaGroupInterpreterGroundwater();
+
+    return new sc::FormulaGroupInterpreterOpenCL();
+}
+
 } // namespace opencl
 
 } // namespace sc
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 2ea09c4..6c930e5 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -216,7 +216,10 @@ FormulaGroupInterpreter *FormulaGroupInterpreter::getStatic()
             msInstance = sc::opencl::createFormulaGroupInterpreter();
 #endif
         if ( !msInstance ) // software fallback
+        {
+            fprintf(stderr, "Create S/W interp\n");
             msInstance = new sc::FormulaGroupInterpreterSoftware();
+        }
     }
 
     return msInstance;


More information about the Libreoffice-commits mailing list