[Libreoffice-commits] core.git: Branch 'feature/calc-group-interpreter-2' - 2 commits - formula/source include/formula sc/inc sc/Library_sc.mk sc/source

Kohei Yoshida kohei.yoshida at gmail.com
Thu Sep 5 08:08:28 PDT 2013


 formula/source/core/api/vectortoken.cxx  |   19 +-
 include/formula/vectortoken.hxx          |   25 ++-
 sc/Library_sc.mk                         |    1 
 sc/inc/column.hxx                        |    3 
 sc/inc/document.hxx                      |    5 
 sc/inc/formulagroup.hxx                  |    9 -
 sc/inc/table.hxx                         |    3 
 sc/inc/token.hxx                         |   24 +++
 sc/inc/types.hxx                         |   13 +
 sc/source/core/data/column2.cxx          |   61 ++++---
 sc/source/core/data/document.cxx         |    8 -
 sc/source/core/data/formulacell.cxx      |   18 +-
 sc/source/core/data/table1.cxx           |   10 -
 sc/source/core/data/types.cxx            |   24 +++
 sc/source/core/inc/interpre.hxx          |   11 +
 sc/source/core/opencl/formulagroupcl.cxx |   22 +-
 sc/source/core/tool/formulagroup.cxx     |   31 +++
 sc/source/core/tool/interpr1.cxx         |  244 ++++++++++++++++++++++---------
 sc/source/core/tool/interpr4.cxx         |   39 ++++
 sc/source/core/tool/interpr5.cxx         |   14 +
 sc/source/core/tool/token.cxx            |   41 +++++
 21 files changed, 489 insertions(+), 136 deletions(-)

New commits:
commit 319dd18f82aeb42dc3cdb49652211ebdbff14d25
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Wed Sep 4 18:33:41 2013 -0400

    Allow storage of string arrays in vector ref tokens.
    
    Change-Id: Id2bc5a0343afeae387d896a9c369586a13081cd5

diff --git a/formula/source/core/api/vectortoken.cxx b/formula/source/core/api/vectortoken.cxx
index 74339397..557e0c0 100644
--- a/formula/source/core/api/vectortoken.cxx
+++ b/formula/source/core/api/vectortoken.cxx
@@ -11,17 +11,24 @@
 
 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) {}
+
 SingleVectorRefToken::SingleVectorRefToken( const double* pArray, size_t nLength ) :
-    FormulaToken(svSingleVectorRef, ocPush), mpArray(pArray), mnArrayLength(nLength) {}
+    FormulaToken(svSingleVectorRef, ocPush), maArray(pArray), mnArrayLength(nLength) {}
+
+SingleVectorRefToken::SingleVectorRefToken( const VectorRefArray& rArray, size_t nLength ) :
+    FormulaToken(svSingleVectorRef, ocPush), maArray(rArray), mnArrayLength(nLength) {}
 
 FormulaToken* SingleVectorRefToken::Clone() const
 {
-    return new SingleVectorRefToken(mpArray, mnArrayLength);
+    return new SingleVectorRefToken(maArray, mnArrayLength);
 }
 
-const double* SingleVectorRefToken::GetArray() const
+const VectorRefArray& SingleVectorRefToken::GetArray() const
 {
-    return mpArray;
+    return maArray;
 }
 
 size_t SingleVectorRefToken::GetArrayLength() const
@@ -30,7 +37,7 @@ size_t SingleVectorRefToken::GetArrayLength() const
 }
 
 DoubleVectorRefToken::DoubleVectorRefToken(
-    const std::vector<const double*>& rArrays, size_t nArrayLength, size_t nRefRowSize, bool bStartFixed, bool bEndFixed ) :
+    const std::vector<VectorRefArray>& rArrays, size_t nArrayLength, size_t nRefRowSize, bool bStartFixed, bool bEndFixed ) :
     FormulaToken(svDoubleVectorRef, ocPush),
     maArrays(rArrays), mnArrayLength(nArrayLength), mnRefRowSize(nRefRowSize), mbStartFixed(bStartFixed), mbEndFixed(bEndFixed) {}
 
@@ -39,7 +46,7 @@ FormulaToken* DoubleVectorRefToken::Clone() const
     return new DoubleVectorRefToken(maArrays, mnArrayLength, mnRefRowSize, mbStartFixed, mbEndFixed);
 }
 
-const std::vector<const double*>& DoubleVectorRefToken::GetArrays() const
+const std::vector<VectorRefArray>& DoubleVectorRefToken::GetArrays() const
 {
     return maArrays;
 }
diff --git a/include/formula/vectortoken.hxx b/include/formula/vectortoken.hxx
index d3d0511..5186ca5 100644
--- a/include/formula/vectortoken.hxx
+++ b/include/formula/vectortoken.hxx
@@ -14,21 +14,36 @@
 
 namespace formula {
 
+struct FORMULA_DLLPUBLIC VectorRefArray
+{
+    union {
+        const double* mpNumericArray;
+        const OUString* mpStringArray;
+    };
+
+    bool mbNumeric;
+
+    VectorRefArray();
+    VectorRefArray( const double* pArray );
+    VectorRefArray( const OUString* pArray );
+};
+
 /**
  * This token represents a single cell reference in a vectorized formula
  * calculation context.
  */
 class FORMULA_DLLPUBLIC SingleVectorRefToken : public FormulaToken
 {
-    const double* mpArray;
+    VectorRefArray maArray;
     size_t mnArrayLength;
 
 public:
     SingleVectorRefToken( const double* pArray, size_t nLength );
+    SingleVectorRefToken( const VectorRefArray& rArray, size_t nLength );
 
     virtual FormulaToken* Clone() const;
 
-    const double* GetArray() const;
+    const VectorRefArray& GetArray() const;
     size_t GetArrayLength() const;
 };
 
@@ -38,7 +53,7 @@ public:
  */
 class FORMULA_DLLPUBLIC DoubleVectorRefToken : public FormulaToken
 {
-    std::vector<const double*> maArrays;
+    std::vector<VectorRefArray> maArrays;
 
     size_t mnArrayLength; /// length of all arrays.
     size_t mnRefRowSize; /// original reference row size. The row size may
@@ -50,11 +65,11 @@ class FORMULA_DLLPUBLIC DoubleVectorRefToken : public FormulaToken
 
 public:
     DoubleVectorRefToken(
-        const std::vector<const double*>& rArrays, size_t nArrayLength, size_t nRefRowSize, bool bStartFixed, bool bEndFixed );
+        const std::vector<VectorRefArray>& rArrays, size_t nArrayLength, size_t nRefRowSize, bool bStartFixed, bool bEndFixed );
 
     virtual FormulaToken* Clone() const;
 
-    const std::vector<const double*>& GetArrays() const;
+    const std::vector<VectorRefArray>& GetArrays() const;
     size_t GetArrayLength() const;
     size_t GetRefRowSize() const;
     bool IsStartFixed() const;
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 49cc24a..f1b53c3 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -35,6 +35,7 @@
 #include <mdds/flat_segment_tree.hpp>
 
 namespace editeng { class SvxBorderLine; }
+namespace formula { struct VectorRefArray; }
 
 namespace sc {
     struct FormulaGroupContext;
@@ -469,7 +470,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 );
+    formula::VectorRefArray FetchVectorRefArray( 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 c74c6c8..b6491cc 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -48,6 +48,8 @@
 #include <boost/scoped_ptr.hpp>
 
 namespace editeng { class SvxBorderLine; }
+namespace formula { struct VectorRefArray; }
+
 namespace sc {
     struct FormulaGroupContext;
     class StartListeningContext;
@@ -57,6 +59,7 @@ namespace sc {
     struct ColumnBlockPosition;
     struct RefUpdateContext;
 }
+
 class SvxFontItem;
 
 class KeyEvent;
@@ -1987,7 +1990,7 @@ public:
     formula::FormulaTokenRef ResolveStaticReference( const ScAddress& rPos );
     formula::FormulaTokenRef ResolveStaticReference( const ScRange& rRange );
 
-    const double* FetchDoubleArray(
+    formula::VectorRefArray FetchVectorRefArray(
         sc::FormulaGroupContext& rCxt, const ScAddress& rPos, SCROW nLength );
 
     SvtBroadcaster* GetBroadcaster( const ScAddress& rPos );
diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
index 9963fc9..776b24d 100644
--- a/sc/inc/formulagroup.hxx
+++ b/sc/inc/formulagroup.hxx
@@ -23,10 +23,13 @@ namespace sc {
 
 struct FormulaGroupContext : boost::noncopyable
 {
-    typedef std::vector<double> DoubleArrayType;
-    typedef boost::ptr_vector<DoubleArrayType> ArrayStoreType;
+    typedef std::vector<double> NumArrayType;
+    typedef std::vector<OUString> StrArrayType;
+    typedef boost::ptr_vector<NumArrayType> NumArrayStoreType;
+    typedef boost::ptr_vector<StrArrayType> StrArrayStoreType;
 
-    ArrayStoreType maArrays;
+    NumArrayStoreType maNumArrays;
+    StrArrayStoreType maStrArrays;
 };
 
 /**
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 06e8151..d36e183 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -49,6 +49,7 @@ namespace com { namespace sun { namespace star {
     }
 } } }
 
+namespace formula { struct VectorRefArray; }
 namespace sc {
     struct FormulaGroupContext;
     class StartListeningContext;
@@ -851,7 +852,7 @@ public:
     ScFormulaVectorState GetFormulaVectorState( SCCOL nCol, SCROW nRow ) const;
     formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol, SCROW nRow );
     formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
-    const double* FetchDoubleArray(
+    formula::VectorRefArray FetchVectorRefArray(
         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 b22b477..5c5e28a 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -63,6 +63,7 @@
 #include <svl/listeneriter.hxx>
 #include <vcl/outdev.hxx>
 #include "formula/errorcodes.hxx"
+#include "formula/vectortoken.hxx"
 
 #include <boost/scoped_ptr.hpp>
 
@@ -2065,7 +2066,7 @@ void ScColumn::FillMatrix( ScMatrix& rMat, size_t nMatCol, SCROW nRow1, SCROW nR
 namespace {
 
 bool appendDouble(
-    sc::FormulaGroupContext::DoubleArrayType& rArray, size_t nLen,
+    sc::FormulaGroupContext::NumArrayType& rArray, size_t nLen,
     sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd )
 {
     size_t nLenRemain = nLen;
@@ -2161,10 +2162,10 @@ bool appendDouble(
 
 }
 
-const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW nRow1, SCROW nRow2 )
+formula::VectorRefArray ScColumn::FetchVectorRefArray( sc::FormulaGroupContext& rCxt, SCROW nRow1, SCROW nRow2 )
 {
     if (nRow1 > nRow2)
-        return NULL;
+        return formula::VectorRefArray();
 
     size_t nLenRequested = nRow2 - nRow1 + 1;
     sc::CellStoreType::position_type aPos = maCells.position(nRow1);
@@ -2175,23 +2176,26 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
         {
             // 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);
+                const double* p = &sc::numeric_block::at(*aPos.first->data, aPos.second);
+                return formula::VectorRefArray(p);
+            }
 
             // 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();
+            rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(it, itEnd));
+            sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.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 formula::VectorRefArray();
 
-            return &rArray[0];
+            return formula::VectorRefArray(&rArray[0]);
         }
         break;
         case sc::element_type_formula:
@@ -2199,8 +2203,8 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
             sal_uInt16 nErr;
             double fVal;
 
-            rCxt.maArrays.push_back(new sc::FormulaGroupContext::DoubleArrayType);
-            sc::FormulaGroupContext::DoubleArrayType& rArray = rCxt.maArrays.back();
+            rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType);
+            sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.back();
             rArray.reserve(nLenRequested);
 
             sc::formula_block::const_iterator it = sc::formula_block::begin(*aPos.first->data);
@@ -2222,13 +2226,13 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
                             rCell.SetErrCode(0);
                             rCell.SetDirtyVar();
                         }
-                        return NULL;
+                        return formula::VectorRefArray();
                     }
 
                     rArray.push_back(fVal);
                 }
 
-                return &rArray[0];
+                return formula::VectorRefArray(&rArray[0]);
             }
 
             // Requested length goes beyond a single block.  Fill the array
@@ -2245,7 +2249,7 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
                         rCell.SetErrCode(0);
                         rCell.SetDirtyVar();
                     }
-                    return NULL;
+                    return formula::VectorRefArray();
                 }
 
                 rArray.push_back(fVal);
@@ -2254,9 +2258,22 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
             // Fill the remaining array with values from the following blocks.
             ++aPos.first;
             if (!appendDouble(rArray, nLenRequested - nLen, aPos.first, maCells.end()))
-                return NULL;
+                return formula::VectorRefArray();
+
+            return formula::VectorRefArray(&rArray[0]);
+        }
+        break;
+        case sc::element_type_string:
+        {
+            if (nLenRequested <= nLen)
+            {
+                // Requested length fits a single block.
+                const OUString* p = &sc::string_block::at(*aPos.first->data, aPos.second);
+                return formula::VectorRefArray(p);
+            }
 
-            return &rArray[0];
+            // TODO: handle cases where the requested length goes beyond the
+            // current block just like we do with numeric array.
         }
         break;
         case sc::element_type_empty:
@@ -2264,27 +2281,27 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
             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];
+                rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(nLenRequested, 0.0));
+                return formula::VectorRefArray(&rCxt.maNumArrays.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();
+            rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(nLen, 0.0));
+            sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.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 formula::VectorRefArray();
 
-            return &rArray[0];
+            return formula::VectorRefArray(&rArray[0]);
         }
         default:
             ;
     }
 
-    return NULL;
+    return formula::VectorRefArray();
 }
 
 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 db97f77..7bf5c66 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -95,6 +95,8 @@
 #include "scopetools.hxx"
 #include "refupdatecontext.hxx"
 
+#include "formula/vectortoken.hxx"
+
 #include <map>
 #include <limits>
 #include <boost/scoped_ptr.hpp>
@@ -1662,14 +1664,14 @@ formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRan
         rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
 }
 
-const double* ScDocument::FetchDoubleArray(
+formula::VectorRefArray ScDocument::FetchVectorRefArray(
     sc::FormulaGroupContext& rCxt, const ScAddress& rPos, SCROW nLength )
 {
     SCTAB nTab = rPos.Tab();
     if (!TableExists(nTab))
-        return NULL;
+        return formula::VectorRefArray();
 
-    return maTabs[nTab]->FetchDoubleArray(rCxt, rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
+    return maTabs[nTab]->FetchVectorRefArray(rCxt, rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
 }
 
 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 64173c9..1c74667 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3396,11 +3396,11 @@ public:
                         // returned array equals or greater than the requested
                         // length.
 
-                        const double* pArray = mrDoc.FetchDoubleArray(mrCxt, aRefPos, nLen);
-                        if (!pArray)
+                        formula::VectorRefArray aArray = mrDoc.FetchVectorRefArray(mrCxt, aRefPos, nLen);
+                        if (!aArray.mpNumericArray)
                             return false;
 
-                        formula::SingleVectorRefToken aTok(pArray, nLen);
+                        formula::SingleVectorRefToken aTok(aArray, nLen);
                         mrGroupTokens.AddToken(aTok);
                     }
                     else
@@ -3444,7 +3444,7 @@ public:
                     bool bAbsLast = !aRef.Ref2.IsRowRel();
                     ScAddress aRefPos = aAbs.aStart;
                     size_t nCols = aAbs.aEnd.Col() - aAbs.aStart.Col() + 1;
-                    std::vector<const double*> aArrays;
+                    std::vector<formula::VectorRefArray> aArrays;
                     aArrays.reserve(nCols);
                     SCROW nArrayLength = nLen;
                     SCROW nRefRowSize = aAbs.aEnd.Row() - aAbs.aStart.Row() + 1;
@@ -3457,11 +3457,11 @@ public:
                     for (SCCOL i = aAbs.aStart.Col(); i <= aAbs.aEnd.Col(); ++i)
                     {
                         aRefPos.SetCol(i);
-                        const double* pArray = mrDoc.FetchDoubleArray(mrCxt, aRefPos, nArrayLength);
-                        if (!pArray)
+                        formula::VectorRefArray aArray = mrDoc.FetchVectorRefArray(mrCxt, aRefPos, nArrayLength);
+                        if (!aArray.mpNumericArray)
                             return false;
 
-                        aArrays.push_back(pArray);
+                        aArrays.push_back(aArray);
                     }
 
                     formula::DoubleVectorRefToken aTok(aArrays, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast);
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 5f409ba..6391eee 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -49,6 +49,8 @@
 #include "scmatrix.hxx"
 #include "refupdatecontext.hxx"
 
+#include "formula/vectortoken.hxx"
+
 #include <vector>
 
 using ::std::vector;
@@ -2148,16 +2150,16 @@ formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol1, SCROW nRo
     return formula::FormulaTokenRef(new ScMatrixToken(pMat));
 }
 
-const double* ScTable::FetchDoubleArray(
+formula::VectorRefArray ScTable::FetchVectorRefArray(
     sc::FormulaGroupContext& rCxt, SCCOL nCol, SCROW nRow1, SCROW nRow2 )
 {
     if (nRow2 < nRow1)
-        return NULL;
+        return formula::VectorRefArray();
 
     if (!ValidCol(nCol) || !ValidRow(nRow1) || !ValidRow(nRow2))
-        return NULL;
+        return formula::VectorRefArray();
 
-    return aCol[nCol].FetchDoubleArray(rCxt, nRow1, nRow2);
+    return aCol[nCol].FetchVectorRefArray(rCxt, nRow1, nRow2);
 }
 
 ScRefCellValue ScTable::GetRefCellValue( SCCOL nCol, SCROW nRow )
diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
index a835c46..daa0dcc 100644
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -792,7 +792,7 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, const ScAddress
                 else if( ocPush == p->GetOpCode() && formula::svDoubleVectorRef == p->GetType())
                 {
                     const formula::DoubleVectorRefToken* pDvr = static_cast< const formula::DoubleVectorRefToken* >( p );
-                    const std::vector< const double* >& rArrays = pDvr->GetArrays();
+                    const std::vector<formula::VectorRefArray>& rArrays = pDvr->GetArrays();
                     uint rArraysSize = rArrays.size();
                     int nMoreColSize = 0;
                     DoubleVectorFormula *SvDoubleTemp = new DoubleVectorFormula();
@@ -801,7 +801,7 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, const ScAddress
                         double *dpMoreColData = NULL;
                         for ( uint loop=0; loop < rArraysSize; loop++ )
                         {
-                            dpOclSrcData = rArrays[loop];
+                            dpOclSrcData = rArrays[loop].mpNumericArray;
                             nSrcDataSize = pDvr->GetArrayLength();
                             nMoreColSize += nSrcDataSize;
                             dpMoreColData = (double *) realloc(dpMoreColData,nMoreColSize * sizeof(double));
@@ -815,7 +815,7 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, const ScAddress
                     }
                     else
                     {
-                        dpOclSrcData = rArrays[0];
+                        dpOclSrcData = rArrays[0].mpNumericArray;
                         nSrcDataSize = pDvr->GetArrayLength();
                         SvDoubleTemp->mdpInputData = dpOclSrcData;
                         SvDoubleTemp->mnInputDataSize = nSrcDataSize;
@@ -830,7 +830,7 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, const ScAddress
                 else if( ocPush == p->GetOpCode() && formula::svSingleVectorRef == p->GetType() )
                 {
                     const formula::SingleVectorRefToken* pSvr = static_cast<const formula::SingleVectorRefToken*>( p );
-                    dpBinaryData = pSvr->GetArray();
+                    dpBinaryData = pSvr->GetArray().mpNumericArray;
                     uint nArrayLen = pSvr->GetArrayLength();
                     SingleVectorFormula *SignleTemp = new SingleVectorFormula() ;
                     if(isSingle)
@@ -884,7 +884,7 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, const ScAddress
                 else if( ocPush == p->GetOpCode() && formula::svDoubleVectorRef == p->GetType())
                 {
                     const formula::DoubleVectorRefToken* pDvr = static_cast< const formula::DoubleVectorRefToken* >( p );
-                    const std::vector< const double* >& rArrays = pDvr->GetArrays();
+                    const std::vector<formula::VectorRefArray>& rArrays = pDvr->GetArrays();
                     unsigned int rArraysSize = rArrays.size();
                     int nMoreColSize = 0;
                     if(rArraysSize > 1)
@@ -892,7 +892,7 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, const ScAddress
                         double *dpMoreColData = NULL;
                         for( uint loop=0; loop < rArraysSize; loop++ )
                         {
-                            dpOclSrcData = rArrays[loop];
+                            dpOclSrcData = rArrays[loop].mpNumericArray;
                             nSrcDataSize = pDvr->GetArrayLength();
                             nMoreColSize += nSrcDataSize;
                             dpMoreColData = (double *) realloc(dpMoreColData,nMoreColSize * sizeof(double));
@@ -907,7 +907,7 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, const ScAddress
                     }
                     else
                     {
-                        dpOclSrcData = rArrays[0];
+                        dpOclSrcData = rArrays[0].mpNumericArray;
                         nSrcDataSize = pDvr->GetArrayLength();
                     }
                     srdDataPush( new SourceData( dpOclSrcData,nSrcDataSize,rArraysSize ) );
@@ -915,7 +915,7 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, const ScAddress
                 else if( ocPush == p->GetOpCode() && formula::svSingleVectorRef == p->GetType() )
                 {
                     const formula::SingleVectorRefToken* pSvr = static_cast<const formula::SingleVectorRefToken*>( p );
-                    dpBinaryData = pSvr->GetArray();
+                    dpBinaryData = pSvr->GetArray().mpNumericArray;
                     nSrcDataSize = pSvr->GetArrayLength();
                     srdDataPush( new SourceData( dpBinaryData, nSrcDataSize ) );
                 }
@@ -1004,11 +1004,11 @@ bool FormulaGroupInterpreterGroundwater::interpretCL(ScDocument& rDoc, const ScA
         RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocPush && p->GetType() == formula::svDoubleVectorRef, "double vector ref expected");
         // Get the range reference vector.
         const formula::DoubleVectorRefToken* pDvr = static_cast<const formula::DoubleVectorRefToken*>(p);
-        const std::vector<const double*>& rArrays = pDvr->GetArrays();
+        const std::vector<formula::VectorRefArray>& rArrays = pDvr->GetArrays();
         RETURN_IF_FAIL(rArrays.size() == 1, "unexpectedly large double ref array");
         RETURN_IF_FAIL(pDvr->GetArrayLength() == (size_t)xGroup->mnLength, "wrong double ref length");
         RETURN_IF_FAIL(pDvr->IsStartFixed() && pDvr->IsEndFixed(), "non-fixed ranges )");
-        pGroundWaterDataArray = rArrays[0];
+        pGroundWaterDataArray = rArrays[0].mpNumericArray;
 
         // Function:
         p = rCode.NextRPN();
@@ -1022,7 +1022,7 @@ bool FormulaGroupInterpreterGroundwater::interpretCL(ScDocument& rDoc, const ScA
 
     // Get the single reference vector.
     const formula::SingleVectorRefToken* pSvr = static_cast<const formula::SingleVectorRefToken*>(p);
-    pArrayToSubtractOneElementFrom = pSvr->GetArray();
+    pArrayToSubtractOneElementFrom = pSvr->GetArray().mpNumericArray;
     RETURN_IF_FAIL(pSvr->GetArrayLength() == (size_t)xGroup->mnLength, "wrong single ref length");
 
     p = rCode.NextRPN();
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 40f4bef..2ea09c4 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -68,14 +68,17 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
                 case formula::svSingleVectorRef:
                 {
                     const formula::SingleVectorRefToken* p2 = static_cast<const formula::SingleVectorRefToken*>(p);
-                    const double* pArray = p2->GetArray();
-                    aCode2.AddDouble(static_cast<size_t>(i) < p2->GetArrayLength() ? pArray[i] : 0.0);
+                    const formula::VectorRefArray& rArray = p2->GetArray();
+                    if (rArray.mbNumeric)
+                        aCode2.AddDouble(static_cast<size_t>(i) < p2->GetArrayLength() ? rArray.mpNumericArray[i] : 0.0);
+                    else
+                        aCode2.AddString(static_cast<size_t>(i) < p2->GetArrayLength() ? rArray.mpStringArray[i] : OUString());
                 }
                 break;
                 case formula::svDoubleVectorRef:
                 {
                     const formula::DoubleVectorRefToken* p2 = static_cast<const formula::DoubleVectorRefToken*>(p);
-                    const std::vector<const double*>& rArrays = p2->GetArrays();
+                    const std::vector<formula::VectorRefArray>& rArrays = p2->GetArrays();
                     size_t nColSize = rArrays.size();
                     size_t nRowStart = p2->IsStartFixed() ? 0 : i;
                     size_t nRowEnd = p2->GetRefRowSize() - 1;
@@ -85,9 +88,19 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
                     ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize, 0.0));
                     for (size_t nCol = 0; nCol < nColSize; ++nCol)
                     {
-                        const double* pArray = rArrays[nCol];
-                        pArray += nRowStart;
-                        pMat->PutDouble(pArray, nRowSize, nCol, 0);
+                        const formula::VectorRefArray& rArray = rArrays[nCol];
+                        if (rArray.mbNumeric)
+                        {
+                            const double* pNums = rArray.mpNumericArray;
+                            pNums += nRowStart;
+                            pMat->PutDouble(pNums, nRowSize, nCol, 0);
+                        }
+                        else
+                        {
+                            const OUString* pStrs = rArray.mpStringArray;
+                            pStrs += nRowStart;
+                            pMat->PutString(pStrs, nRowSize, nCol, 0);
+                        }
                     }
 
                     if (p2->IsStartFixed() && p2->IsEndFixed())
commit 63b106dbfe66b0562ca3d8739aad1ea124084aea
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Wed Sep 4 15:14:47 2013 -0400

    Correctly handle implicit intersection in group interpretation.
    
    Change-Id: I2ea6f41ad4036a6f3f5d99097e83fd988aacd105

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 83e3358..5465960 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -180,6 +180,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
 	sc/source/core/data/table5 \
 	sc/source/core/data/table6 \
 	sc/source/core/data/tabprotection \
+	sc/source/core/data/types \
 	sc/source/core/data/userdat \
 	sc/source/core/data/validat \
 	sc/source/core/tool/addincfg \
diff --git a/sc/inc/token.hxx b/sc/inc/token.hxx
index 9603a87..32cdf5a 100644
--- a/sc/inc/token.hxx
+++ b/sc/inc/token.hxx
@@ -33,6 +33,9 @@
 #include "scmatrix.hxx"
 #include "calcmacros.hxx"
 
+// Matrix token constants.
+#define MATRIX_TOKEN_HAS_RANGE 1
+
 class ScJumpMatrix;
 
 typedef ::std::vector< ScComplexRefData > ScRefList;
@@ -176,6 +179,27 @@ public:
     virtual FormulaToken*       Clone() const { return new ScMatrixToken(*this); }
 };
 
+/**
+ * Token storing matrix that represents values in sheet range. It stores
+ * both the values in matrix form, and the range address the matrix
+ * represents.
+ */
+class ScMatrixRangeToken : public ScToken
+{
+    ScMatrixRef mpMatrix;
+    ScComplexRefData maRef;
+public:
+    ScMatrixRangeToken( const ScMatrixRef& p, const ScComplexRefData& rRef );
+    ScMatrixRangeToken( const ScMatrixRangeToken& r );
+
+    virtual sal_uInt8 GetByte() const;
+    virtual const ScMatrix* GetMatrix() const;
+    virtual ScMatrix* GetMatrix();
+    virtual const ScComplexRefData& GetDoubleRef() const;
+    virtual ScComplexRefData& GetDoubleRef();
+    virtual bool operator==( const formula::FormulaToken& rToken ) const;
+    virtual FormulaToken* Clone() const;
+};
 
 class ScExternalSingleRefToken : public ScToken
 {
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 5c11da5..f03ccc0 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -63,6 +63,19 @@ enum GroupCalcState
     GroupCalcDisabled
 };
 
+struct RangeMatrix
+{
+    ScMatrixRef mpMat;
+    sal_Int32 mnCol1;
+    sal_Int32 mnRow1;
+    sal_Int32 mnCol2;
+    sal_Int32 mnRow2;
+
+    RangeMatrix();
+
+    bool isRangeValid() const;
+};
+
 }
 
 #endif
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index a7491a2..64173c9 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3529,7 +3529,9 @@ bool ScFormulaCell::InterpretFormulaGroup()
             return false;
     }
 
-    if (mxGroup->mbInvariant)
+    // TODO : Disable invariant formula group interpretation for now in order
+    // to get implicit intersection to work.
+    if (mxGroup->mbInvariant && false)
         return InterpretInvariantFormulaGroup();
 
     sc::FormulaGroupContext aCxt;
diff --git a/sc/source/core/data/types.cxx b/sc/source/core/data/types.cxx
new file mode 100644
index 0000000..566d088
--- /dev/null
+++ b/sc/source/core/data/types.cxx
@@ -0,0 +1,24 @@
+/* -*- 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/.
+ */
+
+#include "types.hxx"
+#include "scmatrix.hxx"
+
+namespace sc {
+
+RangeMatrix::RangeMatrix() : mpMat(NULL), mnCol1(-1), mnRow1(-1), mnCol2(-1), mnRow2(-1) {}
+
+bool RangeMatrix::isRangeValid() const
+{
+    return mnCol1 >= 0 && mnRow1 >= 0 && mnCol2 >= 0 && mnRow2 >= 0 && mnCol1 <= mnCol2 && mnRow1 <= mnRow2;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index 8cf87b0..bb9f919 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -51,6 +51,12 @@ class ScToken;
 class ScJumpMatrix;
 struct ScRefCellValue;
 
+namespace sc {
+
+struct RangeMatrix;
+
+}
+
 #define MAXSTACK      (4096 / sizeof(formula::FormulaToken*))
 
 class ScTokenStack
@@ -298,6 +304,7 @@ inline void MatrixDoubleRefToMatrix();      // if MatrixFormula: PopDoubleRefPus
 // If MatrixFormula or ForceArray: ConvertMatrixParameters()
 inline bool MatrixParameterConversion();
 ScMatrixRef PopMatrix();
+sc::RangeMatrix PopRangeMatrix();
 void QueryMatrixType(ScMatrixRef& xMat, short& rRetTypeExpr, sal_uLong& rRetIndexExpr);
 
 void PushDouble(double nVal);
@@ -338,6 +345,8 @@ ScMatrixRef CreateMatrixFromDoubleRef( const formula::FormulaToken* pToken,
 inline ScTokenMatrixMap& GetTokenMatrixMap();
 ScTokenMatrixMap* CreateTokenMatrixMap();
 ScMatrixRef GetMatrix();
+sc::RangeMatrix GetRangeMatrix();
+
 void ScTableOp();                                       // repeated operations
 void ScErrCell();                                       // special handling for
                                                         // error cell
@@ -373,7 +382,7 @@ double Compare();
 /** @param pOptions
         NULL means case sensitivity document option is to be used!
  */
-ScMatrixRef CompareMat( ScCompareOptions* pOptions = NULL );
+sc::RangeMatrix CompareMat( ScCompareOptions* pOptions = NULL );
 ScMatrixRef QueryMat( const ScMatrixRef& pMat, ScCompareOptions& rOptions );
 void ScEqual();
 void ScNotEqual();
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 4ac4b6b..40f4bef 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -93,7 +93,11 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
                     if (p2->IsStartFixed() && p2->IsEndFixed())
                     {
                         // Cached the converted token for absolute range referene.
-                        formula::FormulaTokenRef xTok(new ScMatrixToken(pMat));
+                        ScComplexRefData aRef;
+                        ScRange aRefRange = rTopPos;
+                        aRefRange.aEnd.SetRow(rTopPos.Row() + nRowEnd);
+                        aRef.InitRange(aRefRange);
+                        formula::FormulaTokenRef xTok(new ScMatrixRangeToken(pMat, aRef));
                         aCachedTokens.insert(CachedTokensType::value_type(p, xTok));
                         aCode2.AddToken(*xTok);
                     }
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index da14d42..fd1d224 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -1081,11 +1081,11 @@ double ScInterpreter::Compare()
 }
 
 
-ScMatrixRef ScInterpreter::CompareMat( ScCompareOptions* pOptions )
+sc::RangeMatrix ScInterpreter::CompareMat( ScCompareOptions* pOptions )
 {
     String aVal1, aVal2;
     ScCompare aComp( &aVal1, &aVal2 );
-    ScMatrixRef pMat[2];
+    sc::RangeMatrix aMat[2];
     ScAddress aAdr;
     for( short i = 1; i >= 0; i-- )
     {
@@ -1127,11 +1127,11 @@ ScMatrixRef ScInterpreter::CompareMat( ScCompareOptions* pOptions )
             break;
             case svDoubleRef:
             case svMatrix:
-                pMat[ i ] = GetMatrix();
-                if ( !pMat[ i ] )
+                aMat[i] = GetRangeMatrix();
+                if (!aMat[i].mpMat)
                     SetError( errIllegalParameter);
                 else
-                    pMat[i]->SetErrorInterpreter( NULL);
+                    aMat[i].mpMat->SetErrorInterpreter(NULL);
                     // errors are transported as DoubleError inside matrix
                 break;
             default:
@@ -1139,82 +1139,88 @@ ScMatrixRef ScInterpreter::CompareMat( ScCompareOptions* pOptions )
             break;
         }
     }
-    ScMatrixRef pResMat = NULL;
+
+    sc::RangeMatrix aRes;
     if( !nGlobalError )
     {
-        if ( pMat[0] && pMat[1] )
+        if (aMat[0].mpMat && aMat[1].mpMat)
         {
             SCSIZE nC0, nC1;
             SCSIZE nR0, nR1;
-            pMat[0]->GetDimensions( nC0, nR0 );
-            pMat[1]->GetDimensions( nC1, nR1 );
+            aMat[0].mpMat->GetDimensions(nC0, nR0);
+            aMat[1].mpMat->GetDimensions(nC1, nR1);
             SCSIZE nC = std::max( nC0, nC1 );
             SCSIZE nR = std::max( nR0, nR1 );
-            pResMat = GetNewMat( nC, nR);
-            if ( !pResMat )
-                return NULL;
+            aRes.mpMat = GetNewMat( nC, nR);
+            if (!aRes.mpMat)
+                return aRes;
             for ( SCSIZE j=0; j<nC; j++ )
             {
                 for ( SCSIZE k=0; k<nR; k++ )
                 {
                     SCSIZE nCol = j, nRow = k;
-                    if (    pMat[0]->ValidColRowOrReplicated( nCol, nRow ) &&
-                            pMat[1]->ValidColRowOrReplicated( nCol, nRow ))
+                    if (aMat[0].mpMat->ValidColRowOrReplicated(nCol, nRow) &&
+                        aMat[1].mpMat->ValidColRowOrReplicated(nCol, nRow))
                     {
                         for ( short i=1; i>=0; i-- )
                         {
-                            if ( pMat[i]->IsString(j,k) )
+                            if (aMat[i].mpMat->IsString(j, k))
                             {
                                 aComp.bVal[i] = false;
-                                *aComp.pVal[i] = pMat[i]->GetString(j,k);
-                                aComp.bEmpty[i] = pMat[i]->IsEmpty(j,k);
+                                *aComp.pVal[i] = aMat[i].mpMat->GetString(j, k);
+                                aComp.bEmpty[i] = aMat[i].mpMat->IsEmpty(j, k);
                             }
                             else
                             {
                                 aComp.bVal[i] = true;
-                                aComp.nVal[i] = pMat[i]->GetDouble(j,k);
+                                aComp.nVal[i] = aMat[i].mpMat->GetDouble(j, k);
                                 aComp.bEmpty[i] = false;
                             }
                         }
-                        pResMat->PutDouble( CompareFunc( aComp, pOptions ), j,k );
+                        aRes.mpMat->PutDouble(CompareFunc(aComp, pOptions), j, k);
                     }
                     else
-                        pResMat->PutString( ScGlobal::GetRscString(STR_NO_VALUE), j,k );
+                        aRes.mpMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), j, k);
                 }
             }
         }
-        else if ( pMat[0] || pMat[1] )
+        else if (aMat[0].mpMat || aMat[1].mpMat)
         {
-            short i = ( pMat[0] ? 0 : 1);
+            short i = ( aMat[0].mpMat ? 0 : 1);
             SCSIZE nC, nR;
-            pMat[i]->GetDimensions( nC, nR );
-            pResMat = GetNewMat( nC, nR);
-            if ( !pResMat )
-                return NULL;
+            aMat[i].mpMat->GetDimensions(nC, nR);
+            aRes.mpMat = GetNewMat( nC, nR);
+            if (!aRes.mpMat)
+                return aRes;
+
+            aRes.mnCol1 = aMat[i].mnCol1;
+            aRes.mnRow1 = aMat[i].mnRow1;
+            aRes.mnCol2 = aMat[i].mnCol2;
+            aRes.mnRow2 = aMat[i].mnRow2;
 
             for (SCSIZE j = 0; j < nC; ++j)
             {
                 for (SCSIZE k = 0; k < nR; ++k)
                 {
-                    if ( pMat[i]->IsValue(j,k) )
+                    if (aMat[i].mpMat->IsValue(j, k))
                     {
                         aComp.bVal[i] = true;
-                        aComp.nVal[i] = pMat[i]->GetDouble(j,k);
+                        aComp.nVal[i] = aMat[i].mpMat->GetDouble(j, k);
                         aComp.bEmpty[i] = false;
                     }
                     else
                     {
                         aComp.bVal[i] = false;
-                        *aComp.pVal[i] = pMat[i]->GetString(j,k);
-                        aComp.bEmpty[i] = pMat[i]->IsEmpty(j,k);
+                        *aComp.pVal[i] = aMat[i].mpMat->GetString(j, k);
+                        aComp.bEmpty[i] = aMat[i].mpMat->IsEmpty(j, k);
                     }
-                    pResMat->PutDouble( CompareFunc(aComp, pOptions), j, k);
+                    aRes.mpMat->PutDouble(CompareFunc(aComp, pOptions), j, k);
                 }
             }
         }
     }
     nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
-    return pResMat;
+    return aRes;
 }
 
 
@@ -1228,7 +1234,7 @@ ScMatrixRef ScInterpreter::QueryMat( const ScMatrixRef& pMat, ScCompareOptions&
         PushString(rItem.maString);
     else
         PushDouble(rItem.mfVal);
-    ScMatrixRef pResultMatrix = CompareMat( &rOptions);
+    ScMatrixRef pResultMatrix = CompareMat( &rOptions).mpMat;
     nCurFmtType = nSaveCurFmtType;
     nFuncFmtType = nSaveFuncFmtType;
     if (nGlobalError || !pResultMatrix)
@@ -1264,19 +1270,56 @@ ScMatrixRef ScInterpreter::QueryMat( const ScMatrixRef& pMat, ScCompareOptions&
     return pResultMatrix;
 }
 
+namespace {
+
+double applyImplicitIntersection(const sc::RangeMatrix& rMat, const ScAddress& rPos)
+{
+    if (rMat.mnRow1 <= rPos.Row() && rPos.Row() <= rMat.mnRow2 && rMat.mnCol1 == rMat.mnCol2)
+    {
+        SCROW nOffset = rPos.Row() - rMat.mnRow1;
+        return rMat.mpMat->GetDouble(0, nOffset);
+    }
+
+    if (rMat.mnCol1 <= rPos.Col() && rPos.Col() <= rMat.mnCol2 && rMat.mnRow1 == rMat.mnRow2)
+    {
+        SCROW nOffset = rPos.Col() - rMat.mnCol1;
+        return rMat.mpMat->GetDouble(nOffset, 0);
+    }
+
+    double fVal;
+    rtl::math::setNan(&fVal);
+    return fVal;
+}
+
+}
 
 void ScInterpreter::ScEqual()
 {
     if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
     {
-        ScMatrixRef pMat = CompareMat();
-        if ( !pMat )
+        sc::RangeMatrix aMat = CompareMat();
+        if (!aMat.mpMat)
+        {
             PushIllegalParameter();
-        else
+            return;
+        }
+
+        if (aMat.isRangeValid())
         {
-            pMat->CompareEqual();
-            PushMatrix( pMat );
+            // This matrix represents a range reference. Apply implicit intersection.
+            double fVal = applyImplicitIntersection(aMat, aPos);
+            if (rtl::math::isNan(fVal))
+            {
+                PushError(errCellNoValue);
+                return;
+            }
+
+            PushInt(fVal == 0.0);
+            return;
         }
+
+        aMat.mpMat->CompareEqual();
+        PushMatrix(aMat.mpMat);
     }
     else
         PushInt( Compare() == 0 );
@@ -1287,14 +1330,29 @@ void ScInterpreter::ScNotEqual()
 {
     if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
     {
-        ScMatrixRef pMat = CompareMat();
-        if ( !pMat )
+        sc::RangeMatrix aMat = CompareMat();
+        if (!aMat.mpMat)
+        {
             PushIllegalParameter();
-        else
+            return;
+        }
+
+        if (aMat.isRangeValid())
         {
-            pMat->CompareNotEqual();
-            PushMatrix( pMat );
+            // This matrix represents a range reference. Apply implicit intersection.
+            double fVal = applyImplicitIntersection(aMat, aPos);
+            if (rtl::math::isNan(fVal))
+            {
+                PushError(errCellNoValue);
+                return;
+            }
+
+            PushInt(fVal != 0.0);
+            return;
         }
+
+        aMat.mpMat->CompareNotEqual();
+        PushMatrix(aMat.mpMat);
     }
     else
         PushInt( Compare() != 0 );
@@ -1305,14 +1363,29 @@ void ScInterpreter::ScLess()
 {
     if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
     {
-        ScMatrixRef pMat = CompareMat();
-        if ( !pMat )
+        sc::RangeMatrix aMat = CompareMat();
+        if (!aMat.mpMat)
+        {
             PushIllegalParameter();
-        else
+            return;
+        }
+
+        if (aMat.isRangeValid())
         {
-            pMat->CompareLess();
-            PushMatrix( pMat );
+            // This matrix represents a range reference. Apply implicit intersection.
+            double fVal = applyImplicitIntersection(aMat, aPos);
+            if (rtl::math::isNan(fVal))
+            {
+                PushError(errCellNoValue);
+                return;
+            }
+
+            PushInt(fVal < 0.0);
+            return;
         }
+
+        aMat.mpMat->CompareLess();
+        PushMatrix(aMat.mpMat);
     }
     else
         PushInt( Compare() < 0 );
@@ -1323,14 +1396,29 @@ void ScInterpreter::ScGreater()
 {
     if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
     {
-        ScMatrixRef pMat = CompareMat();
-        if ( !pMat )
+        sc::RangeMatrix aMat = CompareMat();
+        if (!aMat.mpMat)
+        {
             PushIllegalParameter();
-        else
+            return;
+        }
+
+        if (aMat.isRangeValid())
         {
-            pMat->CompareGreater();
-            PushMatrix( pMat );
+            // This matrix represents a range reference. Apply implicit intersection.
+            double fVal = applyImplicitIntersection(aMat, aPos);
+            if (rtl::math::isNan(fVal))
+            {
+                PushError(errCellNoValue);
+                return;
+            }
+
+            PushInt(fVal > 0.0);
+            return;
         }
+
+        aMat.mpMat->CompareGreater();
+        PushMatrix(aMat.mpMat);
     }
     else
         PushInt( Compare() > 0 );
@@ -1341,14 +1429,29 @@ void ScInterpreter::ScLessEqual()
 {
     if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
     {
-        ScMatrixRef pMat = CompareMat();
-        if ( !pMat )
+        sc::RangeMatrix aMat = CompareMat();
+        if (!aMat.mpMat)
+        {
             PushIllegalParameter();
-        else
+            return;
+        }
+
+        if (aMat.isRangeValid())
         {
-            pMat->CompareLessEqual();
-            PushMatrix( pMat );
+            // This matrix represents a range reference. Apply implicit intersection.
+            double fVal = applyImplicitIntersection(aMat, aPos);
+            if (rtl::math::isNan(fVal))
+            {
+                PushError(errCellNoValue);
+                return;
+            }
+
+            PushInt(fVal <= 0.0);
+            return;
         }
+
+        aMat.mpMat->CompareLessEqual();
+        PushMatrix(aMat.mpMat);
     }
     else
         PushInt( Compare() <= 0 );
@@ -1359,14 +1462,29 @@ void ScInterpreter::ScGreaterEqual()
 {
     if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
     {
-        ScMatrixRef pMat = CompareMat();
-        if ( !pMat )
+        sc::RangeMatrix aMat = CompareMat();
+        if (!aMat.mpMat)
+        {
             PushIllegalParameter();
-        else
+            return;
+        }
+
+        if (aMat.isRangeValid())
         {
-            pMat->CompareGreaterEqual();
-            PushMatrix( pMat );
+            // This matrix represents a range reference. Apply implicit intersection.
+            double fVal = applyImplicitIntersection(aMat, aPos);
+            if (rtl::math::isNan(fVal))
+            {
+                PushError(errCellNoValue);
+                return;
+            }
+
+            PushInt(fVal >= 0.0);
+            return;
         }
+
+        aMat.mpMat->CompareGreaterEqual();
+        PushMatrix(aMat.mpMat);
     }
     else
         PushInt( Compare() >= 0 );
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index c6025d4..7beb580 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -1794,6 +1794,45 @@ ScMatrixRef ScInterpreter::PopMatrix()
     return NULL;
 }
 
+sc::RangeMatrix ScInterpreter::PopRangeMatrix()
+{
+    sc::RangeMatrix aRet;
+    if (sp)
+    {
+        switch (pStack[sp-1]->GetType())
+        {
+            case svMatrix:
+            {
+                --sp;
+                FormulaToken* p = pStack[sp];
+                ScToken* p2 = static_cast<ScToken*>(p);
+                aRet.mpMat = p2->GetMatrix();
+                if (aRet.mpMat)
+                {
+                    aRet.mpMat->SetErrorInterpreter(this);
+                    if (p2->GetByte() == MATRIX_TOKEN_HAS_RANGE)
+                    {
+                        const ScComplexRefData& rRef = p2->GetDoubleRef();
+                        if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() && !rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel())
+                        {
+                            aRet.mnCol1 = rRef.Ref1.Col();
+                            aRet.mnRow1 = rRef.Ref1.Row();
+                            aRet.mnCol2 = rRef.Ref2.Col();
+                            aRet.mnRow2 = rRef.Ref2.Row();
+                        }
+                    }
+                }
+                else
+                    SetError( errUnknownVariable);
+            }
+            break;
+            default:
+                aRet.mpMat = PopMatrix();
+        }
+    }
+    return aRet;
+}
+
 void ScInterpreter::QueryMatrixType(ScMatrixRef& xMat, short& rRetTypeExpr, sal_uLong& rRetIndexExpr)
 {
     if (xMat)
diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx
index ad7d799..a033693 100644
--- a/sc/source/core/tool/interpr5.cxx
+++ b/sc/source/core/tool/interpr5.cxx
@@ -494,6 +494,20 @@ ScMatrixRef ScInterpreter::GetMatrix()
     return pMat;
 }
 
+sc::RangeMatrix ScInterpreter::GetRangeMatrix()
+{
+    sc::RangeMatrix aRet;
+    switch (GetRawStackType())
+    {
+        case svMatrix:
+            aRet = PopRangeMatrix();
+        break;
+        default:
+            aRet.mpMat = GetMatrix();
+    }
+    return aRet;
+}
+
 void ScInterpreter::ScMatValue()
 {
     if ( MustHaveParamCount( GetByte(), 3 ) )
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index e5627ff..9f5a7e6 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -804,6 +804,47 @@ bool ScMatrixToken::operator==( const FormulaToken& r ) const
     return FormulaToken::operator==( r ) && pMatrix == static_cast<const ScToken&>(r).GetMatrix();
 }
 
+ScMatrixRangeToken::ScMatrixRangeToken( const ScMatrixRef& p, const ScComplexRefData& rRef ) :
+    ScToken(formula::svMatrix), mpMatrix(p), maRef(rRef) {}
+
+ScMatrixRangeToken::ScMatrixRangeToken( const ScMatrixRangeToken& r ) :
+    ScToken(r), mpMatrix(r.mpMatrix), maRef(r.maRef) {}
+
+sal_uInt8 ScMatrixRangeToken::GetByte() const
+{
+    return MATRIX_TOKEN_HAS_RANGE;
+}
+
+const ScMatrix* ScMatrixRangeToken::GetMatrix() const
+{
+    return mpMatrix.get();
+}
+
+ScMatrix* ScMatrixRangeToken::GetMatrix()
+{
+    return mpMatrix.get();
+}
+
+const ScComplexRefData& ScMatrixRangeToken::GetDoubleRef() const
+{
+    return maRef;
+}
+
+ScComplexRefData& ScMatrixRangeToken::GetDoubleRef()
+{
+    return maRef;
+}
+
+bool ScMatrixRangeToken::operator==( const FormulaToken& r ) const
+{
+    return FormulaToken::operator==(r) && mpMatrix == static_cast<const ScToken&>(r).GetMatrix();
+}
+
+FormulaToken* ScMatrixRangeToken::Clone() const
+{
+    return new ScMatrixRangeToken(*this);
+}
+
 // ============================================================================
 
 ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& r ) :


More information about the Libreoffice-commits mailing list