[Libreoffice-commits] core.git: 25 commits - formula/inc formula/source sc/inc sc/Library_sc.mk sc/qa sc/source

Michael Meeks michael.meeks at suse.com
Tue Mar 19 12:40:48 PDT 2013


 formula/inc/formula/compiler.hrc                  |    4 
 formula/inc/formula/tokenarray.hxx                |    7 
 formula/source/core/api/FormulaCompiler.cxx       |    2 
 formula/source/core/api/token.cxx                 |   21 +-
 sc/Library_sc.mk                                  |    1 
 sc/inc/bigrange.hxx                               |   20 --
 sc/inc/cell.hxx                                   |   41 ++++
 sc/inc/chgtrack.hxx                               |    3 
 sc/inc/column.hxx                                 |   32 +++
 sc/inc/document.hxx                               |   20 ++
 sc/inc/table.hxx                                  |   11 +
 sc/inc/tokenarray.hxx                             |   11 +
 sc/inc/types.hxx                                  |   13 +
 sc/qa/unit/helper/debughelper.hxx                 |    1 
 sc/qa/unit/ucalc.cxx                              |  155 +++++++++++++++++
 sc/source/core/data/bigrange.cxx                  |   30 +++
 sc/source/core/data/cell.cxx                      |   13 +
 sc/source/core/data/cell2.cxx                     |  193 ++++++++++++++++++++++
 sc/source/core/data/column.cxx                    |   19 ++
 sc/source/core/data/column2.cxx                   |   30 +++
 sc/source/core/data/column3.cxx                   |  167 +++++++++++++++++++
 sc/source/core/data/documen9.cxx                  |   13 +
 sc/source/core/data/document.cxx                  |   39 ++++
 sc/source/core/data/table1.cxx                    |   16 +
 sc/source/core/data/table2.cxx                    |   11 +
 sc/source/core/data/table6.cxx                    |   12 +
 sc/source/core/inc/interpre.hxx                   |    4 
 sc/source/core/tool/chgviset.cxx                  |    1 
 sc/source/core/tool/compiler.cxx                  |    1 
 sc/source/core/tool/interpr4.cxx                  |    4 
 sc/source/core/tool/token.cxx                     |  184 ++++++++++++++++++++
 sc/source/filter/excel/excimp8.cxx                |    5 
 sc/source/filter/excel/impop.cxx                  |    6 
 sc/source/filter/excel/xicontent.cxx              |   11 -
 sc/source/filter/excel/xihelper.cxx               |   44 +++--
 sc/source/filter/inc/biff.hxx                     |    1 
 sc/source/filter/inc/qpro.hxx                     |    3 
 sc/source/filter/inc/qprostyle.hxx                |    4 
 sc/source/filter/inc/xicontent.hxx                |    4 
 sc/source/filter/inc/xihelper.hxx                 |   10 -
 sc/source/filter/oox/worksheethelper.cxx          |    3 
 sc/source/filter/rtf/eeimpars.cxx                 |   14 -
 sc/source/filter/xcl97/XclExpChangeTrack.cxx      |    1 
 sc/source/filter/xcl97/XclImpChangeTrack.cxx      |    1 
 sc/source/filter/xml/XMLTrackedChangesContext.cxx |    1 
 sc/source/filter/xml/xmlcelli.cxx                 |    4 
 sc/source/ui/app/transobj.cxx                     |   10 -
 sc/source/ui/condformat/condformatmgr.cxx         |    1 
 sc/source/ui/docshell/impex.cxx                   |    4 
 sc/source/ui/inc/anyrefdg.hxx                     |    2 
 sc/source/ui/inc/condformatmgr.hxx                |    1 
 sc/source/ui/inc/formula.hxx                      |    1 
 sc/source/ui/miscdlgs/anyrefdg.cxx                |    1 
 sc/source/ui/undo/undoblk3.cxx                    |    7 
 sc/source/ui/unoobj/cellsuno.cxx                  |    2 
 sc/source/ui/view/viewfun4.cxx                    |    5 
 sc/source/ui/view/viewutil.cxx                    |    1 
 57 files changed, 1118 insertions(+), 108 deletions(-)

New commits:
commit 42d3adbce63493039e6013f6f3ea15149f2f7507
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Tue Mar 19 17:04:08 2013 +0000

    calm debug, and disable unless SC_FORMULAGROUP=1
    
    Change-Id: I091d43dfa33f440edd50a1c937ef6e6f1930be4e

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 81fa1ea..ec2711f 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -6224,6 +6224,9 @@ void Test::testCellTextWidth()
 
 void Test::testFormulaGrouping()
 {
+    if ( !getenv("SC_FORMULAGROUP") )
+        return;
+
     static const struct {
         const char *pFormula[3];
         const bool  bGroup[3];
diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx
index 0724501..5bd3846 100644
--- a/sc/source/core/data/cell2.cxx
+++ b/sc/source/core/data/cell2.cxx
@@ -1748,7 +1748,7 @@ ScSimilarFormulaDelta *ScFormulaCell::BuildDeltaTo( ScFormulaCell *pOtherCell )
 
     if ( !pThis || !pOther )
     {
-        fprintf( stderr, "Error: no compiled code for cells !" );
+//        fprintf( stderr, "Error: no compiled code for cells !" );
         return NULL;
     }
 
@@ -1817,12 +1817,12 @@ bool ScFormulaCell::InterpretFormulaGroup()
     if( !xGroup.get() )
         return false;
 
-    fprintf( stderr, "Interpret cell %d, %d\n", (int)aPos.Col(), (int)aPos.Row() );
+//    fprintf( stderr, "Interpret cell %d, %d\n", (int)aPos.Col(), (int)aPos.Row() );
 
     if ( xGroup->mpDelta->IsInvariant() )
     {
-        fprintf( stderr, "struck gold - completely invariant for %d items !\n",
-                 (int)xGroup->mnLength );
+//        fprintf( stderr, "struck gold - completely invariant for %d items !\n",
+//                 (int)xGroup->mnLength );
 
         // calculate ourselves:
         InterpretTail( SCITP_NORMAL );
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 4397834..c4c4ec6 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -2119,7 +2119,7 @@ void ScColumn::RebuildFormulaGroups()
         }
     }
 
-#if 1 // OSL_DEBUG_LEVEL > 0
+#if OSL_DEBUG_LEVEL > 0
     if ( maDoubles.size() + maFnGroups.size() > 0 )
     {
         rtl::OUString aStr;
diff --git a/sc/source/core/data/documen9.cxx b/sc/source/core/data/documen9.cxx
index 4a261e8..54e3a08 100644
--- a/sc/source/core/data/documen9.cxx
+++ b/sc/source/core/data/documen9.cxx
@@ -697,6 +697,11 @@ void ScDocument::ApplyAsianEditSettings( ScEditEngineDefaulter& rEngine )
 
 void ScDocument::RebuildFormulaGroups()
 {
+    static const char *pEnableFormulaGroups = getenv("SC_FORMULAGROUP");
+
+    if ( !pEnableFormulaGroups )
+        return;
+
     SCTAB nTab;
     for (nTab=0; nTab < static_cast<SCTAB>(maTabs.size()); nTab++)
         if (maTabs[nTab])
commit 20c4921e901d84a7ef8835ee192e1a7a4b62ee61
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Mar 19 12:51:47 2013 -0400

    Remove use of ScBaseCell and its derivatives outside ScDocument.
    
    This is still work in progress.
    
    Change-Id: Ifcdbefbdd307a2a8819b073d896e90a16980781e

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 4776a70..d8e4a38 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -257,10 +257,12 @@ public:
 
     bool               HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst) const;
 
-                //     TRUE = format for numbers is set
     bool SetString(
         SCROW nRow, SCTAB nTab, const String& rString, formula::FormulaGrammar::AddressConvention eConv,
         ScSetStringParam* pParam = NULL );
+
+    void SetEditText( SCROW nRow, EditTextObject* pEditText );
+
     void        SetValue( SCROW nRow, const double& rVal);
     void        SetError( SCROW nRow, const sal_uInt16 nError);
 
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 98b21eb..91e003e 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -750,7 +750,18 @@ public:
     SC_DLLPUBLIC bool           SetString(
         SCCOL nCol, SCROW nRow, SCTAB nTab, const rtl::OUString& rString,
         ScSetStringParam* pParam = NULL );
-    bool SetString( const ScAddress& rPos, const OUString& rString, ScSetStringParam* pParam = NULL );
+    SC_DLLPUBLIC bool SetString( const ScAddress& rPos, const OUString& rString, ScSetStringParam* pParam = NULL );
+
+    /**
+     * This method manages the lifecycle of the passed edit text object. When
+     * the text is successfully inserted, the cell takes over the ownership of
+     * the text object. If not, the text object gets deleted.
+     *
+     * <p>The caller must ensure that the passed edit text object <i>uses the
+     * SfxItemPool instance returned from ScDocument::GetEditPool()</i>.
+     * This is very important.</p>
+     */
+    SC_DLLPUBLIC void SetEditText( const ScAddress& rPos, EditTextObject* pEditText );
 
     SC_DLLPUBLIC void           SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal );
     void            SetError( SCCOL nCol, SCROW nRow, SCTAB nTab, const sal_uInt16 nError);
@@ -1875,6 +1886,8 @@ private: // CLOOK-Impl-methods
         ScDocument* mpDoc;
     };
 
+    bool TableExists( SCTAB nTab ) const;
+
     void    MergeNumberFormatter(ScDocument* pSrcDoc);
 
     void    ImplCreateOptions(); // Suggestion: switch to on-demand?
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 036dcca..990b0fc 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -299,9 +299,12 @@ public:
     void        PutCell( const ScAddress&, ScBaseCell* pCell );
     void        PutCell( SCCOL nCol, SCROW nRow, ScBaseCell* pCell );
     void        PutCell(SCCOL nCol, SCROW nRow, sal_uLong nFormatIndex, ScBaseCell* pCell);
-                //  TRUE = numberformat set
+
     bool        SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rString,
                            ScSetStringParam* pParam = NULL );
+
+    void SetEditText( SCCOL nCol, SCROW nRow, EditTextObject* pEditText );
+
     void        SetValue( SCCOL nCol, SCROW nRow, const double& rVal );
     void        SetError( SCCOL nCol, SCROW nRow, sal_uInt16 nError);
 
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index fb6c212..4397834 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -1490,6 +1490,10 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
     return bNumFmtSet;
 }
 
+void ScColumn::SetEditText( SCROW nRow, EditTextObject* pEditText )
+{
+    Insert(nRow, new ScEditCell(pEditText, pDocument));
+}
 
 void ScColumn::GetFilterEntries(SCROW nStartRow, SCROW nEndRow, std::vector<ScTypedStrData>& rStrings, bool& rHasDates)
 {
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index f4ef72c..71f4a1f 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -22,6 +22,7 @@
 
 #include <editeng/boxitem.hxx>
 #include <editeng/frmdiritem.hxx>
+#include "editeng/editobj.hxx"
 #include <svx/pageitem.hxx>
 #include <editeng/editeng.hxx>
 #include <svx/svditer.hxx>
@@ -2158,6 +2159,11 @@ ScDocument::NumFmtMergeHandler::~NumFmtMergeHandler()
     mpDoc->pFormatExchangeList = NULL;
 }
 
+bool ScDocument::TableExists( SCTAB nTab ) const
+{
+    return ValidTab(nTab) && static_cast<size_t>(nTab) < maTabs.size() && maTabs[nTab];
+}
+
 void ScDocument::MergeNumberFormatter(ScDocument* pSrcDoc)
 {
     SvNumberFormatter* pThisFormatter = xPoolHelper->GetFormTable();
@@ -2962,6 +2968,17 @@ bool ScDocument::SetString(
     return SetString(rPos.Col(), rPos.Row(), rPos.Tab(), rString, pParam);
 }
 
+void ScDocument::SetEditText( const ScAddress& rPos, EditTextObject* pEditText )
+{
+    if (!TableExists(rPos.Tab()))
+    {
+        delete pEditText;
+        return;
+    }
+
+    maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), pEditText);
+}
+
 void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
 {
     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index c0815c0..015fa67 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -19,6 +19,7 @@
 
 #include "scitems.hxx"
 #include <editeng/boxitem.hxx>
+#include "editeng/editobj.hxx"
 #include <svl/poolcach.hxx>
 #include <unotools/charclass.hxx>
 #include <math.h>
@@ -1322,6 +1323,16 @@ bool ScTable::SetString( SCCOL nCol, SCROW nRow, SCTAB nTabP, const String& rStr
         return false;
 }
 
+void ScTable::SetEditText( SCCOL nCol, SCROW nRow, EditTextObject* pEditText )
+{
+    if (!ValidColRow(nCol, nRow))
+    {
+        delete pEditText;
+        return;
+    }
+
+    aCol[nCol].SetEditText(nRow, pEditText);
+}
 
 void ScTable::SetValue( SCCOL nCol, SCROW nRow, const double& rVal )
 {
diff --git a/sc/source/core/data/table6.cxx b/sc/source/core/data/table6.cxx
index f4a5d25..640ed59 100644
--- a/sc/source/core/data/table6.cxx
+++ b/sc/source/core/data/table6.cxx
@@ -222,7 +222,11 @@ bool ScTable::SearchCell(const SvxSearchItem& rSearchItem, SCCOL nCol, SCROW nRo
                 aCol[nCol].Insert( nRow, pFCell );
             }
             else if ( bMultiLine && aString.indexOf('\n') != -1 )
-                PutCell( nCol, nRow, new ScEditCell( aString, pDocument ) );
+            {
+                ScFieldEditEngine& rEngine = pDocument->GetEditEngine();
+                rEngine.SetText(aString);
+                SetEditText(nCol, nRow, rEngine.CreateTextObject());
+            }
             else
                 aCol[nCol].SetString(nRow, nTab, aString, pDocument->GetAddressConvention());
             // pCell is invalid now (deleted)
diff --git a/sc/source/filter/excel/excimp8.cxx b/sc/source/filter/excel/excimp8.cxx
index 5285247..68ceed5 100644
--- a/sc/source/filter/excel/excimp8.cxx
+++ b/sc/source/filter/excel/excimp8.cxx
@@ -296,8 +296,9 @@ void ImportExcel8::Labelsst( void )
     if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) )
     {
         GetXFRangeBuffer().SetXF( aScPos, nXF );
-        if( ScBaseCell* pCell = GetSst().CreateCell( nSst, nXF ) )
-            GetDoc().PutCell( aScPos.Col(), aScPos.Row(), aScPos.Tab(), pCell );
+        const XclImpString* pXclStr = GetSst().GetString(nSst);
+        if (pXclStr)
+            XclImpStringHelper::SetToDocument(GetDoc(), aScPos, *this, *pXclStr, nXF);
     }
 }
 
diff --git a/sc/source/filter/excel/impop.cxx b/sc/source/filter/excel/impop.cxx
index 41250619..662e426 100644
--- a/sc/source/filter/excel/impop.cxx
+++ b/sc/source/filter/excel/impop.cxx
@@ -338,8 +338,7 @@ void ImportExcel::ReadLabel()
         SetTextEncoding( eOldTextEnc );
 
         GetXFRangeBuffer().SetXF( aScPos, nXFIdx );
-        if( ScBaseCell* pCell = XclImpStringHelper::CreateCell( GetRoot(), aString, nXFIdx ) )
-            GetDoc().PutCell( aScPos, pCell );
+        XclImpStringHelper::SetToDocument(GetDoc(), aScPos, GetRoot(), aString, nXFIdx);
     }
 }
 
@@ -902,8 +901,7 @@ void ImportExcel::Rstring( void )
             aString.ReadFormats( maStrm );
 
         GetXFRangeBuffer().SetXF( aScPos, nXFIdx );
-        if( ScBaseCell* pCell = XclImpStringHelper::CreateCell( *this, aString, nXFIdx ) )
-            GetDoc().PutCell( aScPos, pCell );
+        XclImpStringHelper::SetToDocument(GetDoc(), aScPos, *this, aString, nXFIdx);
     }
 }
 
diff --git a/sc/source/filter/excel/xicontent.cxx b/sc/source/filter/excel/xicontent.cxx
index de6fd13..86ed9de 100644
--- a/sc/source/filter/excel/xicontent.cxx
+++ b/sc/source/filter/excel/xicontent.cxx
@@ -91,14 +91,6 @@ const XclImpString* XclImpSst::GetString( sal_uInt32 nSstIndex ) const
     return (nSstIndex < maStrings.size()) ? &maStrings[ nSstIndex ] : 0;
 }
 
-ScBaseCell* XclImpSst::CreateCell( sal_uInt32 nSstIndex, sal_uInt16 nXFIndex ) const
-{
-    ScBaseCell* pCell = 0;
-    if( const XclImpString* pString = GetString( nSstIndex ) )
-        pCell = XclImpStringHelper::CreateCell( *this, *pString, nXFIndex );
-    return pCell;
-}
-
 // Hyperlinks =================================================================
 
 namespace {
@@ -197,8 +189,7 @@ void lclInsertUrl( const XclImpRoot& rRoot, const String& rUrl, SCCOL nScCol, SC
             }
 
             // The cell will own the text object instance.
-            ScEditCell* pCell = new ScEditCell(rEE.CreateTextObject(), &rDoc);
-            rDoc.PutCell( aScPos, pCell );
+            rDoc.SetEditText(aScPos, rEE.CreateTextObject());
         }
         break;
 
diff --git a/sc/source/filter/excel/xihelper.cxx b/sc/source/filter/excel/xihelper.cxx
index ef840f9..4f114a9 100644
--- a/sc/source/filter/excel/xihelper.cxx
+++ b/sc/source/filter/excel/xihelper.cxx
@@ -25,15 +25,14 @@
 #include <editeng/eeitem.hxx>
 #include <editeng/flditem.hxx>
 #include "document.hxx"
-#include "cell.hxx"
 #include "rangelst.hxx"
 #include "editutil.hxx"
 #include "attrib.hxx"
 #include "xltracer.hxx"
 #include "xistream.hxx"
 #include "xistyle.hxx"
-
 #include "excform.hxx"
+#include "stringutil.hxx"
 
 // Excel->Calc cell address/range conversion ==================================
 
@@ -220,24 +219,39 @@ EditTextObject* XclImpStringHelper::CreateTextObject(
     return lclCreateTextObject( rRoot, rString, EXC_FONTITEM_EDITENG, 0 );
 }
 
-ScBaseCell* XclImpStringHelper::CreateCell(
-        const XclImpRoot& rRoot, const XclImpString& rString, sal_uInt16 nXFIndex )
+void XclImpStringHelper::SetToDocument(
+        ScDocument& rDoc, const ScAddress& rPos, const XclImpRoot& rRoot,
+        const XclImpString& rString, sal_uInt16 nXFIndex )
 {
-    ScBaseCell* pCell = 0;
+    if (!rString.GetText().Len())
+        return;
 
-    if( rString.GetText().Len() )
-    {
-        ::std::auto_ptr< EditTextObject > pTextObj( lclCreateTextObject( rRoot, rString, EXC_FONTITEM_EDITENG, nXFIndex ) );
-        ScDocument& rDoc = rRoot.GetDoc();
+    ::std::auto_ptr< EditTextObject > pTextObj( lclCreateTextObject( rRoot, rString, EXC_FONTITEM_EDITENG, nXFIndex ) );
 
-        if( pTextObj.get() )
-            // ScEditCell will own the text object instance.
-            pCell = new ScEditCell(pTextObj.release(), &rDoc);
+    if (pTextObj.get())
+    {
+        rDoc.SetEditText(rPos, pTextObj.release());
+    }
+    else
+    {
+        OUString aStr = rString.GetText();
+        if (aStr.indexOf('\n') != -1 || aStr.indexOf(CHAR_CR) != -1)
+        {
+            // Multiline content.
+            ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
+            rEngine.SetText(aStr);
+            rDoc.SetEditText(rPos, rEngine.CreateTextObject());
+        }
         else
-            pCell = ScBaseCell::CreateTextCell( rString.GetText(), &rDoc );
+        {
+            // Normal text cell.
+            ScSetStringParam aParam;
+            aParam.mbDetectNumberFormat = false;
+            aParam.mbHandleApostrophe = false;
+            aParam.meSetTextNumFormat = ScSetStringParam::Always;
+            rDoc.SetString(rPos, aStr, &aParam);
+        }
     }
-
-    return pCell;
 }
 
 // Header/footer conversion ===================================================
diff --git a/sc/source/filter/inc/xicontent.hxx b/sc/source/filter/inc/xicontent.hxx
index f4128ad..c5d7aae 100644
--- a/sc/source/filter/inc/xicontent.hxx
+++ b/sc/source/filter/inc/xicontent.hxx
@@ -64,10 +64,6 @@ public:
     /** Returns a pointer to the string with the passed index. */
     const XclImpString* GetString( sal_uInt32 nSstIndex ) const;
 
-    /** Creates a new text cell or edit cell for a Calc document.
-        @param nXFIndex  Index to XF for first text portion (checks escapement). */
-    ScBaseCell*         CreateCell( sal_uInt32 nSstIndex, sal_uInt16 nXFIndex = 0 ) const;
-
 private:
     typedef ::std::vector< XclImpString > XclImpStringVec;
     XclImpStringVec     maStrings;          /// List with all strings in the SST.
diff --git a/sc/source/filter/inc/xihelper.hxx b/sc/source/filter/inc/xihelper.hxx
index 8917a7d..84eb924 100644
--- a/sc/source/filter/inc/xihelper.hxx
+++ b/sc/source/filter/inc/xihelper.hxx
@@ -109,12 +109,10 @@ public:
                             const XclImpRoot& rRoot,
                             const XclImpString& rString );
 
-    /** Creates a new text cell or edit cell for a Calc document.
-        @param nXFIndex  Index to XF for first text portion (for escapement). */
-    static ScBaseCell*  CreateCell(
-                            const XclImpRoot& rRoot,
-                            const XclImpString& rString,
-                            sal_uInt16 nXFIndex = 0 );
+    static void SetToDocument(
+        ScDocument& rDoc, const ScAddress& rPos, const XclImpRoot& rRoot,
+        const XclImpString& rString, sal_uInt16 nXFIndex = 0 );
+
 private:
     /** We don't want anybody to instantiate this class, since it is just a
         collection of static methods. To enforce this, the default constructor
diff --git a/sc/source/filter/oox/worksheethelper.cxx b/sc/source/filter/oox/worksheethelper.cxx
index 3f93056..c83e3c0 100644
--- a/sc/source/filter/oox/worksheethelper.cxx
+++ b/sc/source/filter/oox/worksheethelper.cxx
@@ -1572,10 +1572,9 @@ void WorksheetHelper::putRichString( const CellAddress& rAddress, const RichStri
     ScEditEngineDefaulter& rEE = getEditEngine();
 
     // The cell will own the text object instance returned from convert().
-    ScBaseCell* pNewCell = new ScEditCell(rString.convert(rEE, pFirstPortionFont), &rDoc);
     ScAddress aAddress;
     ScUnoConversion::FillScAddress( aAddress, rAddress );
-    rDoc.PutCell( aAddress, pNewCell );
+    rDoc.SetEditText(aAddress, rString.convert(rEE, pFirstPortionFont));
 }
 
 void WorksheetHelper::putFormulaTokens( const CellAddress& rAddress, const ApiTokenSequence& rTokens ) const
diff --git a/sc/source/filter/rtf/eeimpars.cxx b/sc/source/filter/rtf/eeimpars.cxx
index 5e3dd69..23a4c3c 100644
--- a/sc/source/filter/rtf/eeimpars.cxx
+++ b/sc/source/filter/rtf/eeimpars.cxx
@@ -47,7 +47,6 @@
 #include "docpool.hxx"
 #include "attrib.hxx"
 #include "patattr.hxx"
-#include "cell.hxx"
 #include "eeparser.hxx"
 #include "drwlayer.hxx"
 #include "rangenam.hxx"
@@ -386,19 +385,20 @@ void ScEEImport::WriteToDocument( bool bSizeColsRows, double nOutputFactor, SvNu
                     aStr.SearchAndReplaceAll( (sal_Unicode)'\n', (sal_Unicode)' ' );
 
                     if (bTextFormat)
-                        mpDoc->PutCell( nCol, nRow, nTab, new ScStringCell( aStr));
-                    else
                     {
-                        aParam.mbDetectNumberFormat = bConvertDate;
-                        mpDoc->SetString( nCol, nRow, nTab, aStr, &aParam );
+                        aParam.mbDetectNumberFormat = false;
+                        aParam.meSetTextNumFormat = ScSetStringParam::Always;
                     }
+                    else
+                        aParam.mbDetectNumberFormat = bConvertDate;
+
+                    mpDoc->SetString(nCol, nRow, nTab, aStr, &aParam);
                 }
             }
             else
             {
                 // The cell will own the text object instance.
-                mpDoc->PutCell(
-                    nCol, nRow, nTab, new ScEditCell(mpEngine->CreateTextObject(pE->aSel), mpDoc));
+                mpDoc->SetEditText(ScAddress(nCol,nRow,nTab), mpEngine->CreateTextObject(pE->aSel));
             }
             if ( pE->maImageList.size() )
                 bHasGraphics |= GraphicSize( nCol, nRow, nTab, pE );
diff --git a/sc/source/filter/xml/xmlcelli.cxx b/sc/source/filter/xml/xmlcelli.cxx
index 7126f14..19b9041 100644
--- a/sc/source/filter/xml/xmlcelli.cxx
+++ b/sc/source/filter/xml/xmlcelli.cxx
@@ -1053,14 +1053,14 @@ void ScXMLTableRowCellContext::PutTextCell( const ScAddress& rCurrentPos,
                 // This edit engine uses the SfxItemPool instance returned
                 // from pDoc->GetEditPool() to create the text object, which
                 // is a prerequisite for using this constructor of ScEditCell.
-                pNewCell = new ScEditCell(mpEditEngine->CreateTextObject(), pDoc);
+                pDoc->SetEditText(rCurrentPos, mpEditEngine->CreateTextObject());
             }
         }
         else if ( nCurrentCol > 0 && pOUText && !pOUText->isEmpty() )
             pNewCell = ScBaseCell::CreateTextCell( *pOUText, pDoc );
 
         bDoIncrement = pNewCell != NULL;
-        if ( bDoIncrement )
+        if (bDoIncrement && pNewCell)
             pDoc->PutCell( rCurrentPos, pNewCell );
     }
     // #i56027# This is about setting simple text, not edit cells,
diff --git a/sc/source/ui/app/transobj.cxx b/sc/source/ui/app/transobj.cxx
index 5325fac..b756000 100644
--- a/sc/source/ui/app/transobj.cxx
+++ b/sc/source/ui/app/transobj.cxx
@@ -817,11 +817,17 @@ void ScTransferObj::StripRefs( ScDocument* pDoc,
                 {
                     String aStr = pFCell->GetString();
                     if ( pFCell->IsMultilineResult() )
-                        pNew = new ScEditCell( aStr, pDestDoc );
+                    {
+                        ScFieldEditEngine& rEngine = pDestDoc->GetEditEngine();
+                        rEngine.SetText(aStr);
+                        pDestDoc->SetEditText(ScAddress(nCol,nRow,nDestTab), rEngine.CreateTextObject());
+                    }
                     else
                         pNew = new ScStringCell( aStr );
                 }
-                pDestDoc->PutCell( nCol,nRow,nDestTab, pNew );
+
+                if (pNew)
+                    pDestDoc->PutCell(nCol, nRow, nDestTab, pNew);
 
                 //  number formats
 
diff --git a/sc/source/ui/docshell/impex.cxx b/sc/source/ui/docshell/impex.cxx
index 92a38de..b94146c 100644
--- a/sc/source/ui/docshell/impex.cxx
+++ b/sc/source/ui/docshell/impex.cxx
@@ -1204,7 +1204,9 @@ static bool lcl_PutString(
     else
     {
         bMultiLine = true;
-        pDoc->PutCell( nCol, nRow, nTab, new ScEditCell( rStr, pDoc ) );
+        ScFieldEditEngine& rEngine = pDoc->GetEditEngine();
+        rEngine.SetText(rStr);
+        pDoc->SetEditText(ScAddress(nCol,nRow,nTab), rEngine.CreateTextObject());
     }
     return bMultiLine;
 }
diff --git a/sc/source/ui/undo/undoblk3.cxx b/sc/source/ui/undo/undoblk3.cxx
index e3b3c64..fa3a56c 100644
--- a/sc/source/ui/undo/undoblk3.cxx
+++ b/sc/source/ui/undo/undoblk3.cxx
@@ -49,6 +49,7 @@
 #include "postit.hxx"
 #include "docuno.hxx"
 #include "progress.hxx"
+#include "editutil.hxx"
 
 // STATIC DATA ---------------------------------------------------------------
 
@@ -1023,7 +1024,11 @@ void ScUndoReplace::Undo()
     {
         // aUndoStr may contain line breaks
         if ( aUndoStr.Search('\n') != STRING_NOTFOUND )
-            pDoc->PutCell( aCursorPos, new ScEditCell( aUndoStr, pDoc ) );
+        {
+            ScFieldEditEngine& rEngine = pDoc->GetEditEngine();
+            rEngine.SetText(aUndoStr);
+            pDoc->SetEditText(aCursorPos, rEngine.CreateTextObject());
+        }
         else
             pDoc->SetString( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(), aUndoStr );
         if (pViewShell)
diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx
index 90511ae..cfd864a 100644
--- a/sc/source/ui/unoobj/cellsuno.cxx
+++ b/sc/source/ui/unoobj/cellsuno.cxx
@@ -2359,7 +2359,7 @@ void ScCellRangesBase::SetOnePropertyValue( const SfxItemPropertySimpleEntry* pE
                                 aEngine.QuickSetAttribs( aAttr, ESelection( 0, 0, 0, aStr.Len()));
 
                                 // The cell will own the text object instance.
-                                pDoc->PutCell(aRanges[0]->aStart, new ScEditCell(aEngine.CreateTextObject(), pDoc));
+                                pDoc->SetEditText(aRanges[0]->aStart, aEngine.CreateTextObject());
                             }
                         }
                     }
diff --git a/sc/source/ui/view/viewfun4.cxx b/sc/source/ui/view/viewfun4.cxx
index 33ac576..ea05778 100644
--- a/sc/source/ui/view/viewfun4.cxx
+++ b/sc/source/ui/view/viewfun4.cxx
@@ -414,9 +414,8 @@ void ScViewFunc::DoThesaurus( sal_Bool bRecord )
         if (pCell && pTObject)
         {
             // The cell will own the text object instance.
-            pDoc->PutCell(
-                nCol, nRow, nTab,
-                new ScEditCell(pThesaurusEngine->CreateTextObject(), pDoc));
+            pDoc->SetEditText(
+                ScAddress(nCol,nRow,nTab), pThesaurusEngine->CreateTextObject());
         }
         else
         {
commit d0314afa2fef363eba06e98c70ecdc83e690dcd0
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Mar 19 10:00:07 2013 -0400

    This ScFormulaCell member is not used. Also remove cell.hxx include...
    
    Change-Id: I5d188bb080943acc4b8e4ae44a4c8ef01a837c2f

diff --git a/sc/source/ui/inc/anyrefdg.hxx b/sc/source/ui/inc/anyrefdg.hxx
index 760879a..bba97a7 100644
--- a/sc/source/ui/inc/anyrefdg.hxx
+++ b/sc/source/ui/inc/anyrefdg.hxx
@@ -26,7 +26,6 @@
 #include <sfx2/basedlgs.hxx>
 #include <sfx2/tabdlg.hxx>
 #include "address.hxx"
-#include "cell.hxx"
 #include "compiler.hxx"
 #include "formula/funcutl.hxx"
 #include "IAnyRefDialog.hxx"
@@ -45,7 +44,6 @@ class ScRangeList;
 class ScFormulaReferenceHelper
 {
     IAnyRefDialog*      m_pDlg;
-    ::std::auto_ptr<ScFormulaCell>      pRefCell;
     ::std::auto_ptr<ScCompiler>         pRefComp;
     formula::RefEdit*    pRefEdit;               // active input field
     formula::RefButton*  pRefBtn;                // associated button
diff --git a/sc/source/ui/inc/formula.hxx b/sc/source/ui/inc/formula.hxx
index 1b3790e..997e198 100644
--- a/sc/source/ui/inc/formula.hxx
+++ b/sc/source/ui/inc/formula.hxx
@@ -38,6 +38,7 @@ class ScDocument;
 class ScFuncDesc;
 class ScInputHandler;
 class ScDocShell;
+class ScFormulaCell;
 
 //============================================================================
 typedef ScTabViewShell* PtrTabViewShell;
diff --git a/sc/source/ui/miscdlgs/anyrefdg.cxx b/sc/source/ui/miscdlgs/anyrefdg.cxx
index e1b60ba..cec4522 100644
--- a/sc/source/ui/miscdlgs/anyrefdg.cxx
+++ b/sc/source/ui/miscdlgs/anyrefdg.cxx
@@ -323,7 +323,6 @@ void ScFormulaReferenceHelper::Init()
         ScAddress aCursorPos( nCol, nRow, nTab );
 
         String rStrExp;
-        pRefCell.reset( new ScFormulaCell( pDoc, aCursorPos, rStrExp ) );
         pRefComp.reset( new ScCompiler( pDoc, aCursorPos) );
         pRefComp->SetGrammar( pDoc->GetGrammar() );
         pRefComp->SetCompileForFAP(true);
commit c27b2fb8433758240c00bcd76c7fa322eccdee9c
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Tue Mar 19 16:33:17 2013 +0000

    start of InterpretFormulaGroup.
    
    handle column invariant formulae, sketch comment more work,
    elide Matrix formulae.
    
    Change-Id: I9ce4da26b0ad2407021a10f21c81ada80442c76d

diff --git a/sc/inc/cell.hxx b/sc/inc/cell.hxx
index a096c37..fa5cf23 100644
--- a/sc/inc/cell.hxx
+++ b/sc/inc/cell.hxx
@@ -598,6 +598,7 @@ public:
         { xGroup = xRef; }
     ScSimilarFormulaDelta *BuildDeltaTo( ScFormulaCell *pOther );
     void                   ReleaseDelta( ScSimilarFormulaDelta *pDelta );
+    bool                   InterpretFormulaGroup();
 };
 
 //          Iterator for references in a formula cell
diff --git a/sc/source/core/data/cell.cxx b/sc/source/core/data/cell.cxx
index 5dfd8e5..8305127 100644
--- a/sc/source/core/data/cell.cxx
+++ b/sc/source/core/data/cell.cxx
@@ -1198,11 +1198,6 @@ void ScFormulaCell::Interpret()
     if (!IsDirtyOrInTableOpDirty() || pDocument->GetRecursionHelper().IsInReturn())
         return;     // no double/triple processing
 
-    // Re-build formulae groups - ideally this is done at import / insert / delete etc.
-    // and is reflected in the dependency data ...
-    pDocument->RebuildFormulaGroups();
-
-
     //! HACK:
     //  If the call originates from a Reschedule in DdeLink update, leave dirty
     //  Better: Do a Dde Link Update without Reschedule or do it completely asynchronously!
@@ -1243,7 +1238,8 @@ void ScFormulaCell::Interpret()
     }
     else
     {
-        InterpretTail( SCITP_NORMAL);
+        if ( ! InterpretFormulaGroup() )
+            InterpretTail( SCITP_NORMAL);
     }
 
     // While leaving a recursion or iteration stack, insert its cells to the
diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx
index ca21710..0724501 100644
--- a/sc/source/core/data/cell2.cxx
+++ b/sc/source/core/data/cell2.cxx
@@ -1689,9 +1689,9 @@ void ScFormulaCell::CompileColRowNameFormula()
     }
 }
 
+// we really want to be a lot more descriptive than this
 struct ScSimilarFormulaDelta : std::vector< size_t >
 {
-    // we really want to be a lot more descriptive than this
     bool IsCompatible( ScSimilarFormulaDelta *pDelta )
     {
         if ( size() != pDelta->size() )
@@ -1710,6 +1710,17 @@ struct ScSimilarFormulaDelta : std::vector< size_t >
         push_back( b.nRow - a.nRow );
         push_back( b.nTab - a.nTab );
     }
+
+    /// if the vector is zero then nothing changes down the column.
+    bool IsInvariant() const
+    {
+        for ( size_t i = 0; i < size(); i++ )
+        {
+            if ( (*this)[ i ] != 0 )
+                return false;
+        }
+        return true;
+    }
 };
 
 bool ScFormulaCellGroup::IsCompatible( ScSimilarFormulaDelta *pDelta )
@@ -1722,6 +1733,10 @@ bool ScFormulaCellGroup::IsCompatible( ScSimilarFormulaDelta *pDelta )
 /// formulae should produce pOther
 ScSimilarFormulaDelta *ScFormulaCell::BuildDeltaTo( ScFormulaCell *pOtherCell )
 {
+    // no Matrix formulae yet.
+    if ( GetMatrixFlag() != MM_NONE )
+        return NULL;
+
     // are these formule at all similar ?
     if ( GetHash() != pOtherCell->GetHash() )
         return NULL;
@@ -1787,11 +1802,84 @@ ScSimilarFormulaDelta *ScFormulaCell::BuildDeltaTo( ScFormulaCell *pOtherCell )
     return pDelta;
 }
 
+/// To avoid exposing impl. details of ScSimilarFormulaDelta publicly
 void ScFormulaCell::ReleaseDelta( ScSimilarFormulaDelta *pDelta )
 {
     delete pDelta;
 }
 
+bool ScFormulaCell::InterpretFormulaGroup()
+{
+    // Re-build formulae groups if necessary - ideally this is done at
+    // import / insert / delete etc. and is integral to the data structures
+    pDocument->RebuildFormulaGroups();
+
+    if( !xGroup.get() )
+        return false;
+
+    fprintf( stderr, "Interpret cell %d, %d\n", (int)aPos.Col(), (int)aPos.Row() );
+
+    if ( xGroup->mpDelta->IsInvariant() )
+    {
+        fprintf( stderr, "struck gold - completely invariant for %d items !\n",
+                 (int)xGroup->mnLength );
+
+        // calculate ourselves:
+        InterpretTail( SCITP_NORMAL );
+        for ( sal_Int32 i = 0; i < xGroup->mnLength; i++ )
+        {
+            ScBaseCell *pBaseCell = NULL;
+            pDocument->GetCell( aPos.Col(),
+                                xGroup->mnStart + i,
+                                aPos.Tab(), pBaseCell );
+            assert( pBaseCell != NULL );
+            assert( pBaseCell->GetCellType() == CELLTYPE_FORMULA );
+            ScFormulaCell *pCell = static_cast<ScFormulaCell *>( pBaseCell );
+
+            // FIXME: this set of horrors is unclear to me ... certainly
+            // the above GetCell is profoundly nasty & slow ...
+
+            // Ensure the cell truly has a result:
+            pCell->aResult = aResult;
+            pCell->ResetDirty();
+
+            // FIXME: there is a view / refresh missing here it appears.
+        }
+        return true;
+    }
+    else
+    {
+        // scan the formula ...
+        // have a document method: "Get2DRangeAsDoublesArray" that does the
+        // column-based heavy lifting call it for each absolute range from the
+        // first cell pos in the formula group.
+        //
+        // Project single references to ranges by adding their vector * xGroup->mnLength
+        //
+        // TODO:
+        //    elide multiple dimensional movement in vectors eg. =SUM(A1<1,1>)
+        //    produces a diagonal 'column' that serves no useful purpose for us.
+        //    these should be very rare. Should elide in GetDeltas anyway and
+        //    assert here.
+        //
+        // Having built our input data ...
+        // Throw it, and the formula over to some 'OpenCLCalculage' hook
+        //
+        // on return - release references on these double buffers
+        //
+        // transfer the result to the formula cells (as above)
+        // store the doubles in the columns' maDoubles array for
+        // dependent formulae
+        //
+        // TODO:
+        //    need to abort/fail when we get errors returned and fallback to
+        //    stock interpreting [ I guess ], unless we can use NaN etc. to
+        //    signal errors.
+
+        return false;
+    }
+}
+
 // ============================================================================
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 244033d7148e0badbf5915e21b7f2d67e41bf4eb
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Tue Mar 19 15:52:07 2013 +0000

    get row offset calculation right for groups.
    
    Change-Id: Id65174bbb70a4387cddb985d0556a3bcd692d671

diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index f702b25..fb6c212 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -2028,6 +2028,7 @@ void ScColumn::RebuildFormulaGroups()
         if ( rCur.pCell && rCur.pCell->GetCellType() == CELLTYPE_FORMULA )
             static_cast<ScFormulaCell *>( rCur.pCell )->SetCellGroup( xNone );
     }
+    maFnGroups.clear();
 
     // re-build groups
     ColDoubleEntry *pLastDouble = NULL;
@@ -2049,7 +2050,7 @@ void ScColumn::RebuildFormulaGroups()
             if ( !pLastDouble )
             {
                 pLastDouble = new ColDoubleEntry();
-                pLastDouble->mnStart = i - 1;
+                pLastDouble->mnStart = rPrev.nRow;
                 pLastDouble->maData.push_back(
                         static_cast< ScValueCell * >( rPrev.pCell )->GetValue() );
                 maDoubles.push_back( pLastDouble );
@@ -2081,7 +2082,7 @@ void ScColumn::RebuildFormulaGroups()
             // create a new group ...
             ScFormulaCellGroup *pGroup = new ScFormulaCellGroup();
             pGroup->mpDelta = pDelta;
-            pGroup->mnStart = i - 1;
+            pGroup->mnStart = rPrev.nRow;
             pGroup->mnLength = 2;
 
             xGroup.reset( pGroup );
commit 290d192a9e7f1877b08537da379d09a8a557c94f
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Mar 19 09:40:43 2013 -0400

    Tweak hash generation code to NOT rely on 'i' to shift bits.
    
    Because 'i' can get very large.
    
    Change-Id: I1c7fcafaa60b14f709861f32c56defc7bcaee451

diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 6368ba7..85d6e9a 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -1386,45 +1386,48 @@ void ScTokenArray::GenHash()
                 {
                     // Constant value.
                     sal_uInt8 nVal = p->GetByte();
-                    nHash += (static_cast<size_t>(nVal) << i);
-                    continue;
+                    nHash += static_cast<size_t>(nVal);
                 }
+                break;
                 case svDouble:
                 {
                     // Constant value.
                     double fVal = p->GetDouble();
-                    nHash += (static_cast<size_t>(fVal) << i);
-                    continue;
+                    nHash += static_cast<size_t>(fVal);
                 }
+                break;
                 case svString:
                 {
                     // Constant string.
                     const String& rStr = p->GetString();
-                    nHash += (aHasher(rStr) << i);
-                    continue;
+                    nHash += aHasher(rStr);
                 }
+                break;
                 case svSingleRef:
                 {
                     size_t nVal = HashSingleRef(p->GetSingleRef());
-                    nHash += (nVal << i);
-                    continue;
+                    nHash += nVal;
                 }
+                break;
                 case svDoubleRef:
                 {
                     const ScComplexRefData& rRef = p->GetDoubleRef();
                     size_t nVal1 = HashSingleRef(rRef.Ref1);
                     size_t nVal2 = HashSingleRef(rRef.Ref2);
-                    nHash += (nVal1 << i);
-                    nHash += (nVal2 << i);
-                    continue;
+                    nHash += nVal1;
+                    nHash += nVal2;
                 }
+                break;
                 default:
-                    ;
+                    // Use the opcode value in all the other cases.
+                    nHash += static_cast<size_t>(eOp);
             }
         }
+        else
+            // Use the opcode value in all the other cases.
+            nHash += static_cast<size_t>(eOp);
 
-        // Use the opcode value in all the other cases.
-        nHash += (static_cast<size_t>(eOp) << i);
+        nHash = (nHash << 4) - nHash;
     }
 
     mnHashValue = nHash;
commit 5a637138c0271357619629947e9cc6f90de2c03a
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Tue Mar 19 12:56:51 2013 +0000

    build spans of doubles and cleanup excessive debug.
    
    Change-Id: Ib76596cae12c87825118903cc61b12c251f0c1b7

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 18543f0..4776a70 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -25,6 +25,7 @@
 #include "address.hxx"
 #include "rangenam.hxx"
 #include "types.hxx"
+#include <boost/intrusive_ptr.hpp>
 
 #include <set>
 #include <vector>
@@ -71,6 +72,8 @@ class ScFlatBoolRowSegments;
 struct ScSetStringParam;
 struct ScColWidthParam;
 class ScColumnTextWidthIterator;
+class ScFormulaCellGroup;
+typedef ::boost::intrusive_ptr<ScFormulaCellGroup> ScFormulaCellGroupRef;
 
 struct ScNeededSizeOptions
 {
@@ -89,6 +92,12 @@ struct ColEntry
     ScBaseCell* pCell;
 };
 
+struct ColDoubleEntry
+{
+    SCROW               mnStart;
+    std::vector<double> maData;
+};
+
 class ScColumn
 {
     typedef mdds::multi_type_vector<mdds::mtv::element_block_func> TextWidthType;
@@ -109,6 +118,10 @@ class ScColumn
 
     std::vector<ColEntry> maItems;
 
+    // temporary until we switch to mdds container
+    std::vector<ColDoubleEntry *> maDoubles;
+    std::vector<ScFormulaCellGroupRef> maFnGroups;
+
     ScAttrArray*          pAttrArray;
     ScDocument*           pDocument;
     bool                  bDirtyGroups;     /// formula groups are dirty.
diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx
index f450f75..ca21710 100644
--- a/sc/source/core/data/cell2.cxx
+++ b/sc/source/core/data/cell2.cxx
@@ -1733,15 +1733,12 @@ ScSimilarFormulaDelta *ScFormulaCell::BuildDeltaTo( ScFormulaCell *pOtherCell )
 
     if ( !pThis || !pOther )
     {
-        fprintf( stderr, "no compiled code for cells !" );
+        fprintf( stderr, "Error: no compiled code for cells !" );
         return NULL;
     }
 
     if ( pThisLen != pOtherLen )
-    {
-        fprintf( stderr, "different length formulae !" );
         return NULL;
-    }
 
     // check we are basically the same function
     for ( sal_uInt16 i = 0; i < pThisLen; i++ )
@@ -1750,7 +1747,7 @@ ScSimilarFormulaDelta *ScFormulaCell::BuildDeltaTo( ScFormulaCell *pOtherCell )
              pThis[ i ]->GetOpCode() != pOther[ i ]->GetOpCode() ||
              pThis[ i ]->GetParamCount() != pOther[ i ]->GetParamCount() )
         {
-            fprintf( stderr, "Incompatible type, op-code or param counts\n" );
+//            fprintf( stderr, "Incompatible type, op-code or param counts\n" );
             return NULL;
         }
         switch( pThis[ i ]->GetType() )
@@ -1758,32 +1755,33 @@ ScSimilarFormulaDelta *ScFormulaCell::BuildDeltaTo( ScFormulaCell *pOtherCell )
         case formula::svMatrix:
         case formula::svExternalSingleRef:
         case formula::svExternalDoubleRef:
-            fprintf( stderr, "Ignoring matrix and external references for now\n" );
+//            fprintf( stderr, "Ignoring matrix and external references for now\n" );
             return NULL;
         default:
             break;
         }
     }
 
-    fprintf( stderr, "matching formulae !\n" );
     ScSimilarFormulaDelta *pDelta = new ScSimilarFormulaDelta();
 
     for ( sal_uInt16 i = 0; i < pThisLen; i++ )
     {
-        if ( pThis[i]->GetType() != formula::svSingleRef &&
-             pThis[i]->GetType() != formula::svDoubleRef )
-            continue;
-
         ScToken *pThisTok = static_cast< ScToken * >( pThis[ i ] );
         ScToken *pOtherTok = static_cast< ScToken * >( pOther[ i ] );
 
-        const ScSingleRefData& aThisRef = pThisTok->GetSingleRef();
-        const ScSingleRefData& aOtherRef = pOtherTok->GetSingleRef();
-        pDelta->push_delta( aThisRef, aOtherRef );
-
-        const ScSingleRefData& aThisRef2 = pThisTok->GetSingleRef2();
-        const ScSingleRefData& aOtherRef2 = pOtherTok->GetSingleRef2();
-        pDelta->push_delta( aThisRef2, aOtherRef2 );
+        if ( pThis[i]->GetType() == formula::svSingleRef ||
+             pThis[i]->GetType() == formula::svDoubleRef )
+        {
+            const ScSingleRefData& aThisRef = pThisTok->GetSingleRef();
+            const ScSingleRefData& aOtherRef = pOtherTok->GetSingleRef();
+            pDelta->push_delta( aThisRef, aOtherRef );
+        }
+        if ( pThis[i]->GetType() == formula::svDoubleRef )
+        {
+            const ScSingleRefData& aThisRef2 = pThisTok->GetSingleRef2();
+            const ScSingleRefData& aOtherRef2 = pOtherTok->GetSingleRef2();
+            pDelta->push_delta( aThisRef2, aOtherRef2 );
+        }
     }
 
     return pDelta;
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 6305747..ff8aa35 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -2022,7 +2022,6 @@ void ScColumn::UpdateCompile( bool bForceIfNameInUse )
 {
     if ( !maItems.empty() )
     {
-        fprintf( stderr, "UpdateCompile - column !?\n" );
         for (SCSIZE i = 0; i < maItems.size(); i++)
         {
             ScFormulaCell* p = (ScFormulaCell*) maItems[i].pCell;
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 6ee4495..f702b25 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -2014,6 +2014,12 @@ void ScColumn::RebuildFormulaGroups()
     if ( maItems.empty() || !bDirtyGroups )
         return;
 
+    // clear double groups
+    for (std::vector< ColDoubleEntry *>::iterator it = maDoubles.begin();
+         it != maDoubles.end(); ++it )
+        delete *it;
+    maDoubles.clear();
+
     // clear previous groups
     ScFormulaCellGroupRef xNone;
     for (size_t i = 0; i < maItems.size(); i++)
@@ -2024,21 +2030,42 @@ void ScColumn::RebuildFormulaGroups()
     }
 
     // re-build groups
+    ColDoubleEntry *pLastDouble = NULL;
     for (size_t i = 1; i < maItems.size(); i++)
     {
         ColEntry &rCur = maItems[ i ];
         ColEntry &rPrev = maItems[ i - 1 ];
-        if ( ( rPrev.nRow != rCur.nRow - 1 ) ||               // not contiguous
-             !rCur.pCell || !rPrev.pCell ||                   // paranoia
-             rCur.pCell->GetCellType() != CELLTYPE_FORMULA || // not formulae
-             rPrev.pCell->GetCellType() != CELLTYPE_FORMULA )
+        if ( ( rPrev.nRow != rCur.nRow - 1 ) ||                        // not contiguous
+             !rCur.pCell || !rPrev.pCell ||                            // paranoia
+             rCur.pCell->GetCellType() != rPrev.pCell->GetCellType() ) // same type
+        {
+            pLastDouble = NULL;
+            continue;
+        }
+
+        // collate doubles
+        if ( rCur.pCell->GetCellType() == CELLTYPE_VALUE )
+        {
+            if ( !pLastDouble )
+            {
+                pLastDouble = new ColDoubleEntry();
+                pLastDouble->mnStart = i - 1;
+                pLastDouble->maData.push_back(
+                        static_cast< ScValueCell * >( rPrev.pCell )->GetValue() );
+                maDoubles.push_back( pLastDouble );
+            }
+            pLastDouble->maData.push_back(
+                        static_cast< ScValueCell * >( rCur.pCell )->GetValue() );
+            continue;
+        }
+
+        if ( rCur.pCell->GetCellType() != CELLTYPE_FORMULA )
             continue;
 
         // see if these formulae are similar
         ScFormulaCell *pCur = static_cast< ScFormulaCell *>( rCur.pCell );
         ScFormulaCell *pPrev = static_cast< ScFormulaCell *>( rPrev.pCell );
 
-        fprintf( stderr, "column has contiguous formulae\n" );
         ScSimilarFormulaDelta *pDelta = pPrev->BuildDeltaTo( pCur );
 
         if ( !pDelta )
@@ -2058,6 +2085,8 @@ void ScColumn::RebuildFormulaGroups()
             pGroup->mnLength = 2;
 
             xGroup.reset( pGroup );
+            maFnGroups.push_back( xGroup );
+
             pCur->SetCellGroup( xGroup );
             pPrev->SetCellGroup( xGroup );
         }
@@ -2070,6 +2099,7 @@ void ScColumn::RebuildFormulaGroups()
         }
         else
         {
+#if OSL_DEBUG_LEVEL > 1
             OUString aFormula;
             pCur->GetFormula( aFormula );
             ScAddress aAddr( nCol, rCur.nRow, nTab );
@@ -2079,11 +2109,40 @@ void ScColumn::RebuildFormulaGroups()
             fprintf( stderr, "unusual incompatible extension in cell '%s' of formulae '%s'\n" ,
                      OUStringToOString( aCellAddr, RTL_TEXTENCODING_UTF8 ).getStr(),
                      OUStringToOString( aFormula, RTL_TEXTENCODING_UTF8 ).getStr() );
-
+#endif
             pCur->ReleaseDelta( pDelta );
         }
     }
 
+#if 1 // OSL_DEBUG_LEVEL > 0
+    if ( maDoubles.size() + maFnGroups.size() > 0 )
+    {
+        rtl::OUString aStr;
+        fprintf( stderr, "column %2d has %2d double span(s): ", (int)nCol, (int)maDoubles.size() );
+        for (std::vector< ColDoubleEntry *>::iterator it = maDoubles.begin();
+             it != maDoubles.end(); ++it )
+        {
+            ScRange aDoubleRange( nCol, (*it)->mnStart, nTab,
+                                  nCol, (*it)->mnStart + (*it)->maData.size() - 1, nTab );
+            aDoubleRange.Format( aStr, SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW, pDocument );
+            fprintf( stderr, "%s, ", OUStringToOString( aStr, RTL_TEXTENCODING_UTF8 ).getStr() );
+        }
+        fprintf( stderr, "\n" );
+
+        fprintf( stderr, "column %2d has %2d formula span(s): ", (int)nCol, (int)maFnGroups.size() );
+        for (std::vector< ScFormulaCellGroupRef>::iterator it = maFnGroups.begin();
+             it != maFnGroups.end(); ++it )
+        {
+            ScRange aDoubleRange( nCol, (*it)->mnStart, nTab,
+                                  nCol, (*it)->mnStart + (*it)->mnLength - 1, nTab );
+            aDoubleRange.Format( aStr, SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW, pDocument );
+            fprintf( stderr, "%s, ", OUStringToOString( aStr, RTL_TEXTENCODING_UTF8 ).getStr() );
+        }
+        fprintf( stderr, "\n" );
+    }
+#endif
+
+
     bDirtyGroups = false;
 }
 
commit 9d269e1820efc532a0271f04505c590805a6c48b
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Tue Mar 19 11:52:14 2013 +0000

    use cell hashing algorithm for computing groups.
    
    Update unit tests, dumb-down hashing to compare more for similiarity
    rather than identicality - we want to use this down columns.
    
    Change-Id: Icea731daeb301e1febb2df48b6b46c9faba74e9d

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 63b740b..81fa1ea 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -1222,6 +1222,13 @@ void Test::testFormulaHashAndTag()
         { "=X20", "=X$20", false }, // absolute vs relative
         { "=X20", "=$X20", false }, // absolute vs relative
         { "=X$20", "=$X20", false }, // column absolute vs row absolute
+        // similar enough for merging ...
+        { "=A1", "=B1", true },
+        { "=$A$1", "=$B$1", true },
+        { "=A1", "=C2", true },
+        { "=SUM(A1)", "=SUM(B1)", true },
+        { "=A1+3", "=B1+3", true },
+        { "=A1+7", "=B1+42", false },
     };
 
     for (size_t i = 0; i < SAL_N_ELEMENTS(aHashTests); ++i)
@@ -6221,14 +6228,14 @@ void Test::testFormulaGrouping()
         const char *pFormula[3];
         const bool  bGroup[3];
     } aGroupTests[] = {
-        { { "=B1",  "=C1",  "" },      // single increments
-          { true,   true,    false } },
-        { { "=B1",  "=D1",  "=F1" },   // tripple increments
-          { true,  true,    true } },
-        { { "=B1",  "",     "=C1" },   // a gap
-          { false,  false,  false } },
-        { { "=B1",  "=C1+3", "=C1+D1" }, // confusion: FIXME: =C1+7
-          { false,  false,  false } },
+        { { "=SUM(B1)",  "=SUM(C1)",    "" },            // single increments
+          { true,        true,          false } },
+        { { "=SUM(B1)",  "=SUM(D1)",    "=SUM(F1)" },    // tripple increments
+          { true,        true,          true } },
+        { { "=SUM(B1)",  "",            "=SUM(C1)" },    // a gap
+          { false,       false,         false } },
+        { { "=SUM(B1)",  "=SUM(C1;3)",  "=SUM(D1;3)" }, // similar foo
+          { false,       true,          true } },
     };
 
     m_pDoc->InsertTab( 0, "sheet" );
@@ -6259,7 +6266,7 @@ void Test::testFormulaGrouping()
             if( !!pCur->GetCellGroup().get() ^ aGroupTests[i].bGroup[j] )
             {
                 printf("expected group test %d at row %d to be %d but is %d\n",
-                       i, j, !!pCur->GetCellGroup().get(), aGroupTests[i].bGroup[j]);
+                       i, j, aGroupTests[i].bGroup[j], !!pCur->GetCellGroup().get());
                 CPPUNIT_ASSERT_MESSAGE("Failed", false);
             }
         }
diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx
index 412f85d..f450f75 100644
--- a/sc/source/core/data/cell2.cxx
+++ b/sc/source/core/data/cell2.cxx
@@ -1722,10 +1722,9 @@ bool ScFormulaCellGroup::IsCompatible( ScSimilarFormulaDelta *pDelta )
 /// formulae should produce pOther
 ScSimilarFormulaDelta *ScFormulaCell::BuildDeltaTo( ScFormulaCell *pOtherCell )
 {
-
-// FIXME: TODO - M1
-//    if ( kohei_comparison_hash_not_equal( mnHash, pOther->mnHash )
-//       return NULL;
+    // are these formule at all similar ?
+    if ( GetHash() != pOtherCell->GetHash() )
+        return NULL;
 
     FormulaToken **pThis = pCode->GetCode();
     sal_uInt16     pThisLen = pCode->GetCodeLen();
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 23a2241..6368ba7 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -1348,19 +1348,16 @@ bool ScTokenArray::ImplGetReference( ScRange& rRange, bool bValidOnly ) const
 
 namespace {
 
+// we want to compare for similar not identical formulae
+// so we can't use actual row & column indices.
 size_t HashSingleRef( const ScSingleRefData& rRef )
 {
-    SCsCOL nCol = rRef.Flags.bColRel ? rRef.nRelCol : rRef.nCol;
-    SCsROW nRow = rRef.Flags.bRowRel ? rRef.nRelRow : rRef.nRow;
-    SCsTAB nTab = rRef.Flags.bTabRel ? rRef.nRelTab : rRef.nTab;
-    size_t nVal = nCol;
-    nVal += (nRow << 8);
-    nVal += (nTab << 16);
+    size_t nVal = 0;
 
-    // Embed flag values too.
     nVal += rRef.Flags.bColRel;
     nVal += (rRef.Flags.bRowRel << 1);
     nVal += (rRef.Flags.bTabRel << 2);
+
     return nVal;
 }
 
commit b13550ed57ec438a57f6482d9ea6d16f354eec14
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Mar 18 23:36:55 2013 -0400

    Unit test for formula token array vectorization state.
    
    Change-Id: I91dce36e56d86899ba506beb29df6188f10966c0

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index f255781..63b740b 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -67,6 +67,7 @@
 #include "calcconfig.hxx"
 #include "interpre.hxx"
 #include "columniterator.hxx"
+#include "types.hxx"
 
 #include "formula/IFunctionDescription.hxx"
 
@@ -1203,6 +1204,8 @@ void Test::testFormulaHashAndTag()
 
     ScAddress aPos1(0,0,0), aPos2(1,0,0);
 
+    // Test formula hashing.
+
     struct {
         const char* pFormula1; const char* pFormula2; bool bEqual;
     } aHashTests[] = {
@@ -1245,6 +1248,37 @@ void Test::testFormulaHashAndTag()
         aPos2.IncRow();
     }
 
+    // Go back to row 1.
+    aPos1.SetRow(0);
+    aPos2.SetRow(0);
+
+    // Test formula vectorization state.
+
+    struct {
+        const char* pFormula; ScFormulaVectorState eState;
+    } aVectorTests[] = {
+        { "=SUM(1;2;3;4;5)", FormulaVectorEnabled },
+        { "=NOW()", FormulaVectorDisabled },
+        { "=AVERAGE(X1:Y200)", FormulaVectorCheckReference },
+        { "=MAX(X1:Y200;10;20)", FormulaVectorCheckReference },
+        { "=MIN(10;11;22)", FormulaVectorEnabled },
+        { "=H4", FormulaVectorCheckReference },
+    };
+
+    for (size_t i = 0; i < SAL_N_ELEMENTS(aVectorTests); ++i)
+    {
+        m_pDoc->SetString(aPos1, OUString::createFromAscii(aVectorTests[i].pFormula));
+        ScFormulaVectorState eState = m_pDoc->GetFormulaVectorState(aPos1);
+
+        if (eState != aVectorTests[i].eState)
+        {
+            std::ostringstream os;
+            os << "Unexpected vectorization state: expr:" << aVectorTests[i].pFormula;
+            CPPUNIT_ASSERT_MESSAGE(os.str().c_str(), false);
+        }
+        aPos1.IncRow();
+    }
+
     m_pDoc->DeleteTab(0);
 }
 
commit 307b9bfd17d34bcfc9a2ecdef7802413d79f3694
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Mar 18 23:15:26 2013 -0400

    Reduce dependency on document.hxx. Prefer forward declaration.
    
    Change-Id: I9b0c86735284ec435cceb3acd9bad97a6e523a74

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 066e0b6..48ebfd2 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -98,6 +98,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
 	sc/source/core/data/attrib \
 	sc/source/core/data/autonamecache \
 	sc/source/core/data/bcaslot \
+	sc/source/core/data/bigrange \
 	sc/source/core/data/cell \
 	sc/source/core/data/cell2 \
 	sc/source/core/data/clipparam \
diff --git a/sc/inc/bigrange.hxx b/sc/inc/bigrange.hxx
index 09aaf3b..d36fa9a 100644
--- a/sc/inc/bigrange.hxx
+++ b/sc/inc/bigrange.hxx
@@ -20,14 +20,12 @@
 #ifndef SC_BIGRANGE_HXX
 #define SC_BIGRANGE_HXX
 
-
 #include "global.hxx"
-#include "document.hxx"
-
 
 static const sal_Int32 nInt32Min = 0x80000000;
 static const sal_Int32 nInt32Max = 0x7fffffff;
 
+class ScDocument;
 
 class ScBigAddress
 {
@@ -61,7 +59,7 @@ public:
                 { nColP = nCol; nRowP = nRow; nTabP = nTab; }
 
     inline void     PutInOrder( ScBigAddress& r );
-    inline sal_Bool     IsValid( const ScDocument* ) const;
+    bool IsValid( const ScDocument* pDoc ) const;
     inline ScAddress    MakeAddress() const;
 
     ScBigAddress&   operator=( const ScBigAddress& r )
@@ -101,20 +99,6 @@ inline void ScBigAddress::PutInOrder( ScBigAddress& r )
     }
 }
 
-
-inline sal_Bool ScBigAddress::IsValid( const ScDocument* pDoc ) const
-{   // min/max interval bounds define whole col/row/tab
-    return
-        ((0 <= nCol && nCol <= MAXCOL)
-            || nCol == nInt32Min || nCol == nInt32Max) &&
-        ((0 <= nRow && nRow <= MAXROW)
-            || nRow == nInt32Min || nRow == nInt32Max) &&
-        ((0 <= nTab && nTab < pDoc->GetTableCount())
-            || nTab == nInt32Min || nTab == nInt32Max)
-        ;
-}
-
-
 inline ScAddress ScBigAddress::MakeAddress() const
 {
     SCCOL nColA;
diff --git a/sc/inc/chgtrack.hxx b/sc/inc/chgtrack.hxx
index 4c94932..c4c22a9 100644
--- a/sc/inc/chgtrack.hxx
+++ b/sc/inc/chgtrack.hxx
@@ -27,6 +27,7 @@
 
 #include <tools/datetime.hxx>
 #include <tools/mempool.hxx>
+#include "tools/link.hxx"
 #include <unotools/options.hxx>
 #include "global.hxx"
 #include "bigrange.hxx"
@@ -39,7 +40,7 @@
 
 class ScBaseCell;
 class ScDocument;
-
+class ScFormulaCell;
 
 enum ScChangeActionType
 {
diff --git a/sc/qa/unit/helper/debughelper.hxx b/sc/qa/unit/helper/debughelper.hxx
index 2a560c6..4de5c9d 100644
--- a/sc/qa/unit/helper/debughelper.hxx
+++ b/sc/qa/unit/helper/debughelper.hxx
@@ -36,7 +36,6 @@
 
 #include <rtl/strbuf.hxx>
 #include <rtl/ustring.hxx>
-#include "document.hxx"
 
 #ifdef WNT
 #if !defined NOMINMAX
diff --git a/sc/source/core/data/bigrange.cxx b/sc/source/core/data/bigrange.cxx
new file mode 100644
index 0000000..a48e020
--- /dev/null
+++ b/sc/source/core/data/bigrange.cxx
@@ -0,0 +1,30 @@
+/* -*- 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/.
+ */
+
+#ifndef __SC_BIGRANGE_CXX__
+#define __SC_BIGRANGE_CXX__
+
+#include "bigrange.hxx"
+#include "document.hxx"
+
+bool ScBigAddress::IsValid( const ScDocument* pDoc ) const
+{   // min/max interval bounds define whole col/row/tab
+    return
+        ((0 <= nCol && nCol <= MAXCOL)
+            || nCol == nInt32Min || nCol == nInt32Max) &&
+        ((0 <= nRow && nRow <= MAXROW)
+            || nRow == nInt32Min || nRow == nInt32Max) &&
+        ((0 <= nTab && nTab < pDoc->GetTableCount())
+            || nTab == nInt32Min || nTab == nInt32Max)
+        ;
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index 16eb22c..906f4d6 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -26,7 +26,6 @@
 #include "formula/errorcodes.hxx"
 #include "formula/tokenarray.hxx"
 #include "scdll.hxx"
-#include "document.hxx"
 #include "scmatrix.hxx"
 #include "externalrefmgr.hxx"
 #include "calcconfig.hxx"
@@ -189,8 +188,7 @@ double ConvertStringToValue( const String& );
 double GetCellValue( const ScAddress&, const ScBaseCell* );
 double GetCellValueOrZero( const ScAddress&, const ScBaseCell* );
 double GetValueCellValue( const ScAddress&, const ScValueCell* );
-ScBaseCell* GetCell( const ScAddress& rPos )
-    { return pDok->GetCell( rPos ); }
+ScBaseCell* GetCell( const ScAddress& rPos );
 void GetCellString( String& rStr, const ScBaseCell* pCell );
 sal_uInt16 GetCellErrCode( const ScBaseCell* pCell );
 CellType GetCellType( const ScBaseCell* pCell );
diff --git a/sc/source/core/tool/chgviset.cxx b/sc/source/core/tool/chgviset.cxx
index 1f8547f..2a63d4c 100644
--- a/sc/source/core/tool/chgviset.cxx
+++ b/sc/source/core/tool/chgviset.cxx
@@ -22,6 +22,7 @@
 #include "chgviset.hxx"
 #include "rechead.hxx"
 #include "chgtrack.hxx"
+#include "document.hxx"
 
 // -----------------------------------------------------------------------
 ScChangeViewSettings::~ScChangeViewSettings()
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index 34e4d2b..d78efe6 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -545,6 +545,10 @@ double ScInterpreter::GetCellValueOrZero( const ScAddress& rPos, const ScBaseCel
     return fValue;
 }
 
+ScBaseCell* ScInterpreter::GetCell( const ScAddress& rPos )
+{
+    return pDok->GetCell( rPos );
+}
 
 void ScInterpreter::GetCellString( String& rStr, const ScBaseCell* pCell )
 {
diff --git a/sc/source/filter/inc/biff.hxx b/sc/source/filter/inc/biff.hxx
index 89ceb72..ed739df 100644
--- a/sc/source/filter/inc/biff.hxx
+++ b/sc/source/filter/inc/biff.hxx
@@ -23,7 +23,6 @@
 
 #include <sal/config.h>
 #include "filter.hxx"
-#include "document.hxx"
 
 #include "flttypes.hxx"
 #include "ftools.hxx"
diff --git a/sc/source/filter/inc/qpro.hxx b/sc/source/filter/inc/qpro.hxx
index 5133952..4e6d376 100644
--- a/sc/source/filter/inc/qpro.hxx
+++ b/sc/source/filter/inc/qpro.hxx
@@ -22,7 +22,6 @@
 
 #include <sal/config.h>
 #include "filter.hxx"
-#include "document.hxx"
 #include <tools/string.hxx>
 
 #include "flttypes.hxx"
@@ -30,6 +29,8 @@
 #include "qprostyle.hxx"
 #include "biff.hxx"
 
+class ScDocument;
+
 // Stream wrapper class
 class ScQProReader : public ScBiffReader
 {
diff --git a/sc/source/filter/inc/qprostyle.hxx b/sc/source/filter/inc/qprostyle.hxx
index 482687c..145d146 100644
--- a/sc/source/filter/inc/qprostyle.hxx
+++ b/sc/source/filter/inc/qprostyle.hxx
@@ -23,11 +23,13 @@
 
 #include <sal/config.h>
 #include "filter.hxx"
-#include "document.hxx"
 #include <tools/string.hxx>
 
 #include "flttypes.hxx"
 #include "ftools.hxx"
+#include "address.hxx"
+
+class ScDocument;
 
 class ScQProStyle
 {
diff --git a/sc/source/filter/xcl97/XclExpChangeTrack.cxx b/sc/source/filter/xcl97/XclExpChangeTrack.cxx
index 79a47fb..684d5e1 100644
--- a/sc/source/filter/xcl97/XclExpChangeTrack.cxx
+++ b/sc/source/filter/xcl97/XclExpChangeTrack.cxx
@@ -27,6 +27,7 @@
 #include "xeformula.hxx"
 #include "cell.hxx"
 #include "xcl97rec.hxx"
+#include "document.hxx"
 
 #include <oox/token/tokens.hxx>
 #include <rtl/strbuf.hxx>
diff --git a/sc/source/filter/xcl97/XclImpChangeTrack.cxx b/sc/source/filter/xcl97/XclImpChangeTrack.cxx
index 040b005..e3e31a6 100644
--- a/sc/source/filter/xcl97/XclImpChangeTrack.cxx
+++ b/sc/source/filter/xcl97/XclImpChangeTrack.cxx
@@ -27,6 +27,7 @@
 #include "xihelper.hxx"
 #include "xilink.hxx"
 #include "externalrefmgr.hxx"
+#include "document.hxx"
 
 //___________________________________________________________________
 // class XclImpChangeTrack
diff --git a/sc/source/filter/xml/XMLTrackedChangesContext.cxx b/sc/source/filter/xml/XMLTrackedChangesContext.cxx
index eea74ac..d3b67dd 100644
--- a/sc/source/filter/xml/XMLTrackedChangesContext.cxx
+++ b/sc/source/filter/xml/XMLTrackedChangesContext.cxx
@@ -25,6 +25,7 @@
 #include "cell.hxx"
 #include "textuno.hxx"
 #include "editutil.hxx"
+#include "document.hxx"
 #include <xmloff/xmltoken.hxx>
 #include <xmloff/xmlnmspe.hxx>
 #include <xmloff/nmspmap.hxx>
diff --git a/sc/source/ui/condformat/condformatmgr.cxx b/sc/source/ui/condformat/condformatmgr.cxx
index 977cc36..a18a0ca 100644
--- a/sc/source/ui/condformat/condformatmgr.cxx
+++ b/sc/source/ui/condformat/condformatmgr.cxx
@@ -32,6 +32,7 @@
 #include "globstr.hrc"
 #include "condformatdlg.hxx"
 #include "vcl/msgbox.hxx"
+#include "document.hxx"
 
 #define ITEMID_RANGE 1
 #define ITEMID_CONDITION 2
diff --git a/sc/source/ui/inc/condformatmgr.hxx b/sc/source/ui/inc/condformatmgr.hxx
index d3c9099..be73652 100644
--- a/sc/source/ui/inc/condformatmgr.hxx
+++ b/sc/source/ui/inc/condformatmgr.hxx
@@ -35,7 +35,6 @@
 #include <svtools/headbar.hxx>
 
 #include "conditio.hxx"
-#include "document.hxx"
 
 #include <map>
 
diff --git a/sc/source/ui/view/viewutil.cxx b/sc/source/ui/view/viewutil.cxx
index d24d080..9aa5068 100644
--- a/sc/source/ui/view/viewutil.cxx
+++ b/sc/source/ui/view/viewutil.cxx
@@ -44,6 +44,7 @@
 #include "chgtrack.hxx"
 #include "chgviset.hxx"
 #include "markdata.hxx"
+#include "document.hxx"
 
 #include <svx/svxdlg.hxx>
 #include <svx/dialogs.hrc>
commit d6dbf417850e75cc3d4ac9e45ed9db3ffac507ed
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Mar 18 22:55:26 2013 -0400

    Add accessor to ScDocument for formula cell's vectorization state.
    
    Change-Id: I3c781764c6375dadb173bc5ab3cfb79857e2aeca

diff --git a/sc/inc/cell.hxx b/sc/inc/cell.hxx
index 944c8dc..a096c37 100644
--- a/sc/inc/cell.hxx
+++ b/sc/inc/cell.hxx
@@ -429,6 +429,8 @@ public:
 
     size_t GetHash() const;
 
+    ScFormulaVectorState GetVectorState() const;
+
     void            GetFormula( rtl::OUString& rFormula,
                                 const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ) const;
     void            GetFormula( rtl::OUStringBuffer& rBuffer,
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 8147c06..18543f0 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -24,6 +24,7 @@
 #include "global.hxx"
 #include "address.hxx"
 #include "rangenam.hxx"
+#include "types.hxx"
 
 #include <set>
 #include <vector>
@@ -410,7 +411,11 @@ public:
 
     size_t GetFormulaHash( SCROW nRow ) const;
 
+    ScFormulaVectorState GetFormulaVectorState( SCROW nRow ) const;
+
 private:
+    const ScFormulaCell* FetchFormulaCell( SCROW nRow ) const;
+
     ScBaseCell* CloneCell(SCSIZE nIndex, sal_uInt16 nFlags, ScDocument& rDestDoc, const ScAddress& rDestPos) const;
 
     SCROW FindNextVisibleRowWithContent(SCROW nRow, bool bForward) const;
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 7d23b89..98b21eb 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1856,6 +1856,8 @@ public:
 
     size_t GetFormulaHash( const ScAddress& rPos ) const;
 
+    ScFormulaVectorState GetFormulaVectorState( const ScAddress& rPos ) const;
+
 private: // CLOOK-Impl-methods
 
     /**
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 2e8b697..036dcca 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -29,6 +29,7 @@
 #include "sortparam.hxx"
 #include "compressedarray.hxx"
 #include "postit.hxx"
+#include "types.hxx"
 
 #include <set>
 #include <map>
@@ -798,6 +799,8 @@ public:
 
     size_t GetFormulaHash( SCCOL nCol, SCROW nRow ) const;
 
+    ScFormulaVectorState GetFormulaVectorState( SCCOL nCol, SCROW nRow ) const;
+
 private:
     void        FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                                 sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd,
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index 5c09d28..2449074 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -24,6 +24,7 @@
 #include "scmatrix.hxx"
 #include <tools/solar.h>
 #include "scdllapi.h"
+#include "types.hxx"
 #include <formula/tokenarray.hxx>
 
 struct ScRawToken;
@@ -34,17 +35,10 @@ class SC_DLLPUBLIC ScTokenArray : public formula::FormulaTokenArray
 {
     friend class ScCompiler;
 
-    /**
-     * When vectorization is enabled, we could potentially mass-calculate a
-     * series of formula token arrays in adjacent formula cells in one step,
-     * provided that they all contain identical set of tokens.
-     */
-    enum VectorState { Disabled = 0, Enabled, CheckReference };
-
     bool                    ImplGetReference( ScRange& rRange, bool bValidOnly ) const;
 
     size_t mnHashValue;
-    VectorState meVectorState;
+    ScFormulaVectorState meVectorState;
 
 public:
     ScTokenArray();
@@ -56,6 +50,8 @@ public:
     void GenHash();
     size_t GetHash() const;
 
+    ScFormulaVectorState GetVectorState() const;
+
     /// Exactly and only one range (valid or deleted)
     bool    IsReference( ScRange& rRange ) const;
     /// Exactly and only one valid range (no #REF!s)
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index bb454a9..99d78f4 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -36,6 +36,19 @@ class ScMatrix;
 typedef ::boost::intrusive_ptr<ScMatrix>        ScMatrixRef;
 typedef ::boost::intrusive_ptr<const ScMatrix>  ScConstMatrixRef;
 
+/**
+ * When vectorization is enabled, we could potentially mass-calculate a
+ * series of formula token arrays in adjacent formula cells in one step,
+ * provided that they all contain identical set of tokens.
+ */
+enum ScFormulaVectorState
+{
+    FormulaVectorDisabled = 0,
+    FormulaVectorEnabled,
+    FormulaVectorCheckReference,
+    FormulaVectorUnknown
+};
+
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 6bde797..f255781 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -1205,7 +1205,7 @@ void Test::testFormulaHashAndTag()
 
     struct {
         const char* pFormula1; const char* pFormula2; bool bEqual;
-    } aTests[] = {
+    } aHashTests[] = {
         { "=1", "=2", false }, // different constants
         { "=SUM(1;2;3;4;5)", "=AVERAGE(1;2;3;4;5)", false }, // different functions
         { "=C2*3", "=D2*3", true },  // relative references
@@ -1221,16 +1221,16 @@ void Test::testFormulaHashAndTag()
         { "=X$20", "=$X20", false }, // column absolute vs row absolute
     };
 
-    for (size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i)
+    for (size_t i = 0; i < SAL_N_ELEMENTS(aHashTests); ++i)
     {
-        m_pDoc->SetString(aPos1, OUString::createFromAscii(aTests[i].pFormula1));
-        m_pDoc->SetString(aPos2, OUString::createFromAscii(aTests[i].pFormula2));
+        m_pDoc->SetString(aPos1, OUString::createFromAscii(aHashTests[i].pFormula1));
+        m_pDoc->SetString(aPos2, OUString::createFromAscii(aHashTests[i].pFormula2));
         size_t nHashVal1 = m_pDoc->GetFormulaHash(aPos1);
         size_t nHashVal2 = m_pDoc->GetFormulaHash(aPos2);
 
         std::ostringstream os;
-        os << "(expr1:" << aTests[i].pFormula1 << "; expr2:" << aTests[i].pFormula2 << ")";
-        if (aTests[i].bEqual)
+        os << "(expr1:" << aHashTests[i].pFormula1 << "; expr2:" << aHashTests[i].pFormula2 << ")";
+        if (aHashTests[i].bEqual)
         {
             os << " Error: these hashes should be equal." << endl;
             CPPUNIT_ASSERT_MESSAGE(os.str().c_str(), nHashVal1 == nHashVal2);
diff --git a/sc/source/core/data/cell.cxx b/sc/source/core/data/cell.cxx
index c2247c1..5dfd8e5 100644
--- a/sc/source/core/data/cell.cxx
+++ b/sc/source/core/data/cell.cxx
@@ -889,6 +889,11 @@ size_t ScFormulaCell::GetHash() const
     return pCode->GetHash();
 }
 
+ScFormulaVectorState ScFormulaCell::GetVectorState() const
+{
+    return pCode->GetVectorState();
+}
+
 void ScFormulaCell::GetFormula( rtl::OUStringBuffer& rBuffer,
                                 const FormulaGrammar::Grammar eGrammar ) const
 {
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index ea4be5b..17d951d 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1527,20 +1527,32 @@ void ScColumn::SetScriptType( SCROW nRow, sal_uInt8 nType )
 
 size_t ScColumn::GetFormulaHash( SCROW nRow ) const
 {
+    const ScFormulaCell* pCell = FetchFormulaCell(nRow);
+    return pCell ? pCell->GetHash() : 0;
+}
+
+ScFormulaVectorState ScColumn::GetFormulaVectorState( SCROW nRow ) const
+{
+    const ScFormulaCell* pCell = FetchFormulaCell(nRow);
+    return pCell ? pCell->GetVectorState() : FormulaVectorUnknown;
+}
+
+const ScFormulaCell* ScColumn::FetchFormulaCell( SCROW nRow ) const
+{
     if (!ValidRow(nRow))
-        return 0;
+        return NULL;
 
     SCSIZE nIndex;
     if (!Search(nRow, nIndex))
         // cell not found.
-        return 0;
+        return NULL;
 
     const ScBaseCell* pCell = maItems[nIndex].pCell;
     if (pCell->GetCellType() != CELLTYPE_FORMULA)
         // Not a formula cell.
-        return 0;
+        return NULL;
 
-    return static_cast<const ScFormulaCell*>(pCell)->GetHash();
+    return static_cast<const ScFormulaCell*>(pCell);
 }
 
 void ScColumn::FindDataAreaPos(SCROW& rRow, bool bDown) const
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 1f237d1..f4ef72c 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1561,6 +1561,15 @@ size_t ScDocument::GetFormulaHash( const ScAddress& rPos ) const
     return maTabs[nTab]->GetFormulaHash(rPos.Col(), rPos.Row());
 }
 
+ScFormulaVectorState ScDocument::GetFormulaVectorState( const ScAddress& rPos ) const
+{
+    SCTAB nTab = rPos.Tab();
+    if (!ValidTab(nTab) || static_cast<size_t>(nTab) >= maTabs.size() || !maTabs[nTab])
+        return FormulaVectorUnknown;
+
+    return maTabs[nTab]->GetFormulaVectorState(rPos.Col(), rPos.Row());
+}
+
 bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
 {
     if ( rOld == rNew )
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index ee90ae4..12ab3d3 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2104,6 +2104,14 @@ size_t ScTable::GetFormulaHash( SCCOL nCol, SCROW nRow ) const
     return aCol[nCol].GetFormulaHash(nRow);
 }
 
+ScFormulaVectorState ScTable::GetFormulaVectorState( SCCOL nCol, SCROW nRow ) const
+{
+    if (!ValidCol(nCol))
+        return FormulaVectorUnknown;
+
+    return aCol[nCol].GetFormulaVectorState(nRow);
+}
+
 void ScTable::DeleteConditionalFormat( sal_uLong nIndex )
 {
     mpCondFormatList->erase(nIndex);
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index a5eb796..23a2241 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -1249,7 +1249,7 @@ bool ScTokenArray::AddFormulaToken(const com::sun::star::sheet::FormulaToken& _a
 
 void ScTokenArray::CheckToken( const FormulaToken& r )
 {
-    if (meVectorState == Disabled)
+    if (meVectorState == FormulaVectorDisabled)
         // It's already disabled.  No more checking needed.
         return;
 
@@ -1270,7 +1270,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r )
                 // Don't change the state.
             break;
             default:
-                meVectorState = Disabled;
+                meVectorState = FormulaVectorDisabled;
         }
         return;
     }
@@ -1289,7 +1289,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r )
             case svSingleRef:
             case svDoubleRef:
                 // Depends on the reference state.
-                meVectorState = CheckReference;
+                meVectorState = FormulaVectorCheckReference;
             break;
             case svError:
             case svEmptyCell:
@@ -1311,7 +1311,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r )
             case svSubroutine:
             case svUnknown:
                 // We don't support vectorization on these.
-                meVectorState = Disabled;
+                meVectorState = FormulaVectorDisabled;
             default:
                 ;
         }
@@ -1438,6 +1438,11 @@ size_t ScTokenArray::GetHash() const
     return mnHashValue;
 }
 
+ScFormulaVectorState ScTokenArray::GetVectorState() const
+{
+    return meVectorState;
+}
+
 bool ScTokenArray::IsReference( ScRange& rRange ) const
 {
     return ImplGetReference( rRange, false );
@@ -1453,7 +1458,7 @@ bool ScTokenArray::IsValidReference( ScRange& rRange ) const
 ScTokenArray::ScTokenArray() :
     FormulaTokenArray(),
     mnHashValue(0),
-    meVectorState(Enabled)
+    meVectorState(FormulaVectorEnabled)
 {
 }
 
commit 292ffa80bc2665107d7011b2180c2659835d6c26
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Mar 18 22:10:49 2013 -0400

    First cut on checking the token array on whether we could do vectorization.
    
    Not tested yet.
    
    Change-Id: I87f8a8595229d8d8e83526dc0334891d253cf2c7

diff --git a/formula/inc/formula/compiler.hrc b/formula/inc/formula/compiler.hrc
index 8acfff6..053947c 100644
--- a/formula/inc/formula/compiler.hrc
+++ b/formula/inc/formula/compiler.hrc
@@ -94,6 +94,8 @@
 #define SC_OPCODE_NEG_SUB            62
 #define SC_OPCODE_STOP_UN_OP         63
 
+#define SC_OPCODE_START_FUNCTION     65
+
 /*** Functions without parameters ***/
 #define SC_OPCODE_START_NO_PAR       65
 #define SC_OPCODE_PI                 65
@@ -403,6 +405,8 @@
 #define SC_OPCODE_STOP_2_PAR        407
 #define SC_OPCODE_LAST_OPCODE_ID    406     /* last OpCode */
 
+#define SC_OPCODE_STOP_FUNCTION     407
+
 /*** Internal ***/
 #define SC_OPCODE_INTERNAL_BEGIN   9999
 #define SC_OPCODE_TTT              9999
diff --git a/formula/inc/formula/tokenarray.hxx b/formula/inc/formula/tokenarray.hxx
index 42c9212..875b055 100644
--- a/formula/inc/formula/tokenarray.hxx
+++ b/formula/inc/formula/tokenarray.hxx
@@ -192,6 +192,12 @@ public:
     */
     bool Fill(const com::sun::star::uno::Sequence< com::sun::star::sheet::FormulaToken >& _aSequence, ExternalReferenceHelper* _pRef = NULL);
 
+    /**
+     * Do some checking based on the individual tokens. For now, we use this
+     * only to check whether we can vectorize the token array.
+     */
+    virtual void CheckToken( const FormulaToken& t );
+
     FormulaToken* AddToken( const FormulaToken& );
     FormulaToken* AddString( const sal_Unicode* pStr );
     FormulaToken* AddString( const String& rStr );
diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx
index 8750555..84180f0 100644
--- a/formula/source/core/api/token.cxx
+++ b/formula/source/core/api/token.cxx
@@ -708,6 +708,11 @@ void FormulaTokenArray::Clear()
     ClearRecalcMode();
 }
 
+void FormulaTokenArray::CheckToken( const FormulaToken& /*r*/ )
+{
+    // Do nothing.
+}
+
 FormulaToken* FormulaTokenArray::AddToken( const FormulaToken& r )
 {
     return Add( r.Clone() );
@@ -724,6 +729,7 @@ FormulaToken* FormulaTokenArray::Add( FormulaToken* t )
         pCode = new FormulaToken*[ MAXCODE ];
     if( nLen < MAXCODE-1 )
     {
+        CheckToken(*t);
         pCode[ nLen++ ] = t;
         if( t->GetOpCode() == ocPush
             && ( t->GetType() == svSingleRef || t->GetType() == svDoubleRef ) )
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index e3b7d56..5c09d28 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -33,9 +33,18 @@ struct ScComplexRefData;
 class SC_DLLPUBLIC ScTokenArray : public formula::FormulaTokenArray
 {
     friend class ScCompiler;
+
+    /**
+     * When vectorization is enabled, we could potentially mass-calculate a
+     * series of formula token arrays in adjacent formula cells in one step,
+     * provided that they all contain identical set of tokens.
+     */
+    enum VectorState { Disabled = 0, Enabled, CheckReference };
+
     bool                    ImplGetReference( ScRange& rRange, bool bValidOnly ) const;
 
     size_t mnHashValue;
+    VectorState meVectorState;
 
 public:
     ScTokenArray();
@@ -61,6 +70,7 @@ public:
 
     formula::FormulaToken* AddRawToken( const ScRawToken& );
     virtual bool AddFormulaToken(const com::sun::star::sheet::FormulaToken& _aToken,formula::ExternalReferenceHelper* _pRef);
+    virtual void CheckToken( const formula::FormulaToken& r );
     virtual formula::FormulaToken* AddOpCode( OpCode eCode );
     /** ScSingleRefToken with ocPush. */
     formula::FormulaToken* AddSingleReference( const ScSingleRefData& rRef );
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index b595177..a5eb796 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -1246,6 +1246,78 @@ bool ScTokenArray::AddFormulaToken(const com::sun::star::sheet::FormulaToken& _a
     }
     return bError;
 }
+
+void ScTokenArray::CheckToken( const FormulaToken& r )
+{
+    if (meVectorState == Disabled)
+        // It's already disabled.  No more checking needed.
+        return;
+
+    OpCode eOp = r.GetOpCode();
+
+    if (SC_OPCODE_START_FUNCTION <= eOp && eOp < SC_OPCODE_STOP_FUNCTION)
+    {
+        // This is a function opcode. For now, we only support vectorization
+        // for min, max, sum and average.
+        switch (eOp)
+        {
+            case ocAverage:
+            case ocMin:
+            case ocMinA:
+            case ocMax:
+            case ocMaxA:
+            case ocSum:
+                // Don't change the state.
+            break;
+            default:
+                meVectorState = Disabled;
+        }
+        return;
+    }
+
+    if (eOp == ocPush)
+    {
+        // This is a stack variable.  See if this is a reference.
+
+        switch (r.GetType())
+        {
+            case svByte:
+            case svDouble:
+            case svString:
+                // Don't change the state.
+            break;
+            case svSingleRef:
+            case svDoubleRef:
+                // Depends on the reference state.
+                meVectorState = CheckReference;
+            break;
+            case svError:
+            case svEmptyCell:
+            case svExternal:
+            case svExternalDoubleRef:
+            case svExternalName:
+            case svExternalSingleRef:
+            case svFAP:
+            case svHybridCell:
+            case svHybridValueCell:
+            case svIndex:
+            case svJump:
+            case svJumpMatrix:
+            case svMatrix:
+            case svMatrixCell:
+            case svMissing:
+            case svRefList:
+            case svSep:
+            case svSubroutine:
+            case svUnknown:
+                // We don't support vectorization on these.
+                meVectorState = Disabled;
+            default:
+                ;
+        }
+    }
+}
+
 bool ScTokenArray::ImplGetReference( ScRange& rRange, bool bValidOnly ) const
 {
     bool bIs = false;
@@ -1380,13 +1452,15 @@ bool ScTokenArray::IsValidReference( ScRange& rRange ) const
 
 ScTokenArray::ScTokenArray() :
     FormulaTokenArray(),
-    mnHashValue(0)
+    mnHashValue(0),
+    meVectorState(Enabled)
 {
 }
 
 ScTokenArray::ScTokenArray( const ScTokenArray& rArr ) :
     FormulaTokenArray(rArr),
-    mnHashValue(rArr.mnHashValue)
+    mnHashValue(rArr.mnHashValue),
+    meVectorState(rArr.meVectorState)
 {
 }
 
@@ -1411,6 +1485,8 @@ ScTokenArray* ScTokenArray::Clone() const
     p->nError = nError;
     p->bHyperLink = bHyperLink;
     p->mnHashValue = mnHashValue;
+    p->meVectorState = meVectorState;
+
     FormulaToken** pp;
     if( nLen )
     {
commit 3a09e0078ae0e25c7317baed471a9c7c1f729794
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Mar 18 21:11:53 2013 -0400

    Use initializer in ctor.
    
    Change-Id: I2721c083e26654f5ce5cc636d652cb4d50a158ad

diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx
index 150be29..8750555 100644
--- a/formula/source/core/api/token.cxx
+++ b/formula/source/core/api/token.cxx
@@ -581,12 +581,17 @@ bool FormulaTokenArray::HasNameOrColRowName() const
 }
 
 
-FormulaTokenArray::FormulaTokenArray()
+FormulaTokenArray::FormulaTokenArray() :
+    pCode(NULL),
+    pRPN(NULL),
+    nLen(0),
+    nRPN(0),
+    nIndex(0),
+    nError(0),
+    nRefs(0),
+    nMode(RECALCMODE_NORMAL),
+    bHyperLink(false)
 {
-    pCode = NULL; pRPN = NULL;
-    nError = nLen = nIndex = nRPN = nRefs = 0;
-    bHyperLink = false;
-    ClearRecalcMode();
 }
 
 FormulaTokenArray::FormulaTokenArray( const FormulaTokenArray& rArr )
commit d65e83b32f7cf8227984b843a783d55c384c373b
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Mar 18 19:40:08 2013 -0400

    Generate token array hash exactly once, when the string is tokenized.
    
    And CompileString() is the place to do it, to the best of my knowledge.
    
    Change-Id: I249df5d09aa288eacc2b2c7ad6e5fc947a3c225f

diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index 01993e9..e3b7d56 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -35,6 +35,8 @@ class SC_DLLPUBLIC ScTokenArray : public formula::FormulaTokenArray
     friend class ScCompiler;
     bool                    ImplGetReference( ScRange& rRange, bool bValidOnly ) const;
 
+    size_t mnHashValue;
+
 public:
     ScTokenArray();
     /// Assignment with references to ScToken entries (not copied!)
@@ -42,6 +44,7 @@ public:
    virtual ~ScTokenArray();
     ScTokenArray* Clone() const;    /// True copy!
 
+    void GenHash();
     size_t GetHash() const;
 
     /// Exactly and only one range (valid or deleted)
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index b4850ca..07f4673 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -3951,6 +3951,7 @@ ScTokenArray* ScCompiler::CompileString( const String& rFormula )
 
     // remember pArr, in case a subsequent CompileTokenArray() is executed.
     ScTokenArray* pNew = new ScTokenArray( aArr );
+    pNew->GenHash();
     pArr = pNew;
 
     if (!maExternalFiles.empty())
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index a19f2e3..b595177 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -1294,7 +1294,7 @@ size_t HashSingleRef( const ScSingleRefData& rRef )
 
 }
 
-size_t ScTokenArray::GetHash() const
+void ScTokenArray::GenHash()
 {
     static OUStringHash aHasher;
 
@@ -1357,7 +1357,13 @@ size_t ScTokenArray::GetHash() const
         // Use the opcode value in all the other cases.
         nHash += (static_cast<size_t>(eOp) << i);
     }
-    return nHash;
+
+    mnHashValue = nHash;
+}
+
+size_t ScTokenArray::GetHash() const
+{
+    return mnHashValue;
 }
 
 bool ScTokenArray::IsReference( ScRange& rRange ) const
@@ -1372,11 +1378,15 @@ bool ScTokenArray::IsValidReference( ScRange& rRange ) const
 
 ////////////////////////////////////////////////////////////////////////////
 
-ScTokenArray::ScTokenArray()
+ScTokenArray::ScTokenArray() :
+    FormulaTokenArray(),
+    mnHashValue(0)
 {
 }
 
-ScTokenArray::ScTokenArray( const ScTokenArray& rArr ) : FormulaTokenArray(rArr)
+ScTokenArray::ScTokenArray( const ScTokenArray& rArr ) :
+    FormulaTokenArray(rArr),
+    mnHashValue(rArr.mnHashValue)
 {
 }
 
@@ -1384,8 +1394,6 @@ ScTokenArray::~ScTokenArray()
 {
 }
 
-
-
 ScTokenArray& ScTokenArray::operator=( const ScTokenArray& rArr )
 {
     Clear();
@@ -1402,6 +1410,7 @@ ScTokenArray* ScTokenArray::Clone() const
     p->nMode = nMode;
     p->nError = nError;
     p->bHyperLink = bHyperLink;
+    p->mnHashValue = mnHashValue;
     FormulaToken** pp;
     if( nLen )
     {
commit 0a0deec6f1e5c3e3100673daa6ef244b2d8ff8bf
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Mar 18 17:14:51 2013 -0400

    Fix indentation.
    
    Change-Id: Ia277ac4e9eeb34a2b0244ebb5f09c428f5cf2b64

diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx
index 3cfb903..3e990cb 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -2018,7 +2018,7 @@ void FormulaCompiler::LocalizeString( String& /*rName*/ )
 void FormulaCompiler::PushTokenArray( FormulaTokenArray* pa, bool bTemp )
 {
     if ( bAutoCorrect && !pStack )
-        {   // don't merge stacked subroutine code into entered formula
+    {   // don't merge stacked subroutine code into entered formula
         aCorrectedFormula += aCorrectedSymbol;
         aCorrectedSymbol.Erase();
     }
commit 945853ba9e9f1188c87f527866e7e8a1fd967a35
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Mar 18 18:29:22 2013 -0400

    Fix build breakage.
    
    Change-Id: I94b9d17a045a9c17d9e97aa582d7572e0a21809b

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index f530890..6bde797 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -117,7 +117,7 @@ public:
     void testCollator();
     void testRangeList();
     void testInput();
-    void testFormulaGrouping();
+    void testFormulaHashAndTag();
     void testCellFunctions();
     void testCopyToDocument();
     /**
@@ -276,7 +276,7 @@ public:
     CPPUNIT_TEST(testCollator);
     CPPUNIT_TEST(testRangeList);
     CPPUNIT_TEST(testInput);
-    CPPUNIT_TEST(testFormulaGrouping);
+    CPPUNIT_TEST(testFormulaHashAndTag);
     CPPUNIT_TEST(testCellFunctions);
     CPPUNIT_TEST(testCopyToDocument);
     CPPUNIT_TEST(testSheetsFunc);
@@ -1197,7 +1197,7 @@ void testFuncINDIRECT(ScDocument* pDoc)
     }
 }
 
-void Test::testFormulaGrouping()
+void Test::testFormulaHashAndTag()
 {
     m_pDoc->InsertTab(0, "Test");
 
diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx
index db14d58..412f85d 100644
--- a/sc/source/core/data/cell2.cxx
+++ b/sc/source/core/data/cell2.cxx
@@ -42,6 +42,8 @@
 #include "patattr.hxx"
 #include <rtl/strbuf.hxx>
 
+#include <cstdio>
+
 using namespace formula;
 
 // STATIC DATA -----------------------------------------------------------
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index ede8b92..6305747 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -37,6 +37,7 @@
 
 #include <cstring>
 #include <map>
+#include <cstdio>
 
 using ::editeng::SvxBorderLine;
 using namespace formula;
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 5ddb3f1..6ee4495 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -48,6 +48,8 @@
 
 #include <com/sun/star/i18n/LocaleDataItem.hpp>
 
+#include <cstdio>
+
 using ::com::sun::star::i18n::LocaleDataItem;
 using ::rtl::OUString;
 using ::rtl::OUStringBuffer;
commit fedb28e84614ac6c0f6076cca56b6c2c8b832198
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Mon Mar 18 21:29:58 2013 +0000

    add initial formula group unit tests.
    
    Change-Id: Id4dd3cc0d3d8a4db641e316d2eda44a5b94105c7

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 3e9a14d..f530890 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -33,6 +33,7 @@
 #include <osl/file.hxx>
 
 #include "scdll.hxx"
+#include "cell.hxx"
 #include "document.hxx"
 #include "stringutil.hxx"
 #include "scmatrix.hxx"
@@ -266,6 +267,11 @@ public:
     void testAnchoredRotatedShape();
     void testCellTextWidth();
 
+    /**
+     * Test formula & formula grouping
+     */
+    void testFormulaGrouping();
+
     CPPUNIT_TEST_SUITE(Test);
     CPPUNIT_TEST(testCollator);
     CPPUNIT_TEST(testRangeList);
@@ -328,6 +334,7 @@ public:
     CPPUNIT_TEST(testDeleteCol);
     CPPUNIT_TEST(testAnchoredRotatedShape);
     CPPUNIT_TEST(testCellTextWidth);
+    CPPUNIT_TEST(testFormulaGrouping);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -6174,6 +6181,57 @@ void Test::testCellTextWidth()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testFormulaGrouping()
+{
+    static const struct {
+        const char *pFormula[3];
+        const bool  bGroup[3];
+    } aGroupTests[] = {
+        { { "=B1",  "=C1",  "" },      // single increments
+          { true,   true,    false } },
+        { { "=B1",  "=D1",  "=F1" },   // tripple increments
+          { true,  true,    true } },
+        { { "=B1",  "",     "=C1" },   // a gap
+          { false,  false,  false } },
+        { { "=B1",  "=C1+3", "=C1+D1" }, // confusion: FIXME: =C1+7
+          { false,  false,  false } },
+    };
+
+    m_pDoc->InsertTab( 0, "sheet" );
+
+    for (size_t i = 0; i < SAL_N_ELEMENTS( aGroupTests ); i++)
+    {
+        for (size_t j = 0; j < SAL_N_ELEMENTS( aGroupTests[0].pFormula ); j++)
+        {
+            OUString aFormula = OUString::createFromAscii(aGroupTests[i].pFormula[j]);
+            m_pDoc->SetString(0, (SCROW)j, 0, aFormula);
+        }
+        m_pDoc->RebuildFormulaGroups();
+
+        for (size_t j = 0; j < SAL_N_ELEMENTS( aGroupTests[0].pFormula ); j++)
+        {
+            ScBaseCell *pCell = NULL;
+            m_pDoc->GetCell( 0, (SCROW)j, 0, pCell );
+            if( !pCell )
+            {
+                CPPUNIT_ASSERT_MESSAGE("invalid empty cell", !aGroupTests[i].bGroup[j]);
+                continue;
+            }
+            CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pCell != NULL);
+            CPPUNIT_ASSERT_MESSAGE("Cell wrong type.",
+                                   pCell->GetCellType() == CELLTYPE_FORMULA);
+            ScFormulaCell *pCur = static_cast< ScFormulaCell *>( pCell );
+
+            if( !!pCur->GetCellGroup().get() ^ aGroupTests[i].bGroup[j] )
+            {
+                printf("expected group test %d at row %d to be %d but is %d\n",
+                       i, j, !!pCur->GetCellGroup().get(), aGroupTests[i].bGroup[j]);
+                CPPUNIT_ASSERT_MESSAGE("Failed", false);
+            }
+        }
+    }
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
 
 }
diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx
index 4cb4eb8..db14d58 100644
--- a/sc/source/core/data/cell2.cxx
+++ b/sc/source/core/data/cell2.cxx
@@ -1752,11 +1752,15 @@ ScSimilarFormulaDelta *ScFormulaCell::BuildDeltaTo( ScFormulaCell *pOtherCell )
             fprintf( stderr, "Incompatible type, op-code or param counts\n" );
             return NULL;
         }
-        if( pThis[ i ]->GetType() == formula::svMatrix ||
-            pOther[ i ]->GetType() == formula::svMatrix )
+        switch( pThis[ i ]->GetType() )
         {
-            fprintf( stderr, "Ignoring matrix formulae for now\n" );
+        case formula::svMatrix:
+        case formula::svExternalSingleRef:
+        case formula::svExternalDoubleRef:
+            fprintf( stderr, "Ignoring matrix and external references for now\n" );
             return NULL;
+        default:
+            break;
         }
     }
 
@@ -1765,6 +1769,10 @@ ScSimilarFormulaDelta *ScFormulaCell::BuildDeltaTo( ScFormulaCell *pOtherCell )
 
     for ( sal_uInt16 i = 0; i < pThisLen; i++ )
     {
+        if ( pThis[i]->GetType() != formula::svSingleRef &&
+             pThis[i]->GetType() != formula::svDoubleRef )
+            continue;
+
         ScToken *pThisTok = static_cast< ScToken * >( pThis[ i ] );
         ScToken *pOtherTok = static_cast< ScToken * >( pOther[ i ] );
 
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index d288625..5ddb3f1 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -2036,7 +2036,6 @@ void ScColumn::RebuildFormulaGroups()
         ScFormulaCell *pCur = static_cast< ScFormulaCell *>( rCur.pCell );
         ScFormulaCell *pPrev = static_cast< ScFormulaCell *>( rPrev.pCell );
 
-#ifdef BUILD_FORMULA_GROUPS
         fprintf( stderr, "column has contiguous formulae\n" );
         ScSimilarFormulaDelta *pDelta = pPrev->BuildDeltaTo( pCur );
 
@@ -2081,9 +2080,6 @@ void ScColumn::RebuildFormulaGroups()
 
             pCur->ReleaseDelta( pDelta );
         }
-#else
-        (void)pCur; (void) pPrev;
-#endif
     }
 
     bDirtyGroups = false;
commit aed58c04a8483881e4592565587aaf08e6239672
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Mar 18 16:28:11 2013 -0400

    Embed reference tokens in the generated hash values.
    
    Also make the test code a bit easier to extend.
    
    Change-Id: Ib4e381cc139231884999c9d0dc9f51201e11f807

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index b6addd1..3e9a14d 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -1196,47 +1196,47 @@ void Test::testFormulaGrouping()
 
     ScAddress aPos1(0,0,0), aPos2(1,0,0);
 
-    // simplest cases.
-    m_pDoc->SetString(aPos1, "=1");
-    size_t nHashVal1 = m_pDoc->GetFormulaHash(aPos1);
-    m_pDoc->SetString(aPos2, "=2");
-    size_t nHashVal2 = m_pDoc->GetFormulaHash(aPos2);
-    CPPUNIT_ASSERT_MESSAGE("These hashes should differ.", nHashVal1 != nHashVal2);
-
-    // different cell functions.
-    aPos1.IncRow();
-    aPos2.IncRow();
-    m_pDoc->SetString(aPos1, "=SUM(1;2;3;4;5)");
-    m_pDoc->SetString(aPos2, "=AVERAGE(1;2;3;4;5)");
-    nHashVal1 = m_pDoc->GetFormulaHash(aPos1);
-    nHashVal2 = m_pDoc->GetFormulaHash(aPos2);
-    CPPUNIT_ASSERT_MESSAGE("These hashes should differ.", nHashVal1 != nHashVal2);
-
-    // same relative references.
-    aPos1.IncRow();
-    aPos2.IncRow();
-    m_pDoc->SetString(aPos1, "=A2*3");
-    m_pDoc->SetString(aPos2, "=B2*3");
-    nHashVal1 = m_pDoc->GetFormulaHash(aPos1);
-    nHashVal2 = m_pDoc->GetFormulaHash(aPos2);
-    CPPUNIT_ASSERT_MESSAGE("These hashes should be equal.", nHashVal1 == nHashVal2);
-
-    m_pDoc->SetString(aPos2, "=B2*4"); // Change the constant.
-    nHashVal2 = m_pDoc->GetFormulaHash(aPos2);
-    CPPUNIT_ASSERT_MESSAGE("These hashes should differ.", nHashVal1 != nHashVal2);
-
-    m_pDoc->SetString(aPos1, "=A2*4"); // Change the constant again to make it "equal".
-    nHashVal1 = m_pDoc->GetFormulaHash(aPos1);
-    CPPUNIT_ASSERT_MESSAGE("These hashes should be equal.", nHashVal1 == nHashVal2);
-
-    // string constant vs numeric constant.
-    aPos1.IncRow();
-    aPos2.IncRow();
-    m_pDoc->SetString(aPos1, "=3*4*5");
-    m_pDoc->SetString(aPos2, "=3*4*\"foo\"");
-    nHashVal1 = m_pDoc->GetFormulaHash(aPos1);
-    nHashVal2 = m_pDoc->GetFormulaHash(aPos2);
-    CPPUNIT_ASSERT_MESSAGE("These hashes should differ.", nHashVal1 != nHashVal2);
+    struct {
+        const char* pFormula1; const char* pFormula2; bool bEqual;
+    } aTests[] = {
+        { "=1", "=2", false }, // different constants
+        { "=SUM(1;2;3;4;5)", "=AVERAGE(1;2;3;4;5)", false }, // different functions
+        { "=C2*3", "=D2*3", true },  // relative references
+        { "=C2*3", "=D2*4", false }, // different constants
+        { "=C2*4", "=D2*4", true },  // relative references
+        { "=3*4*5", "=3*4*\"foo\"", false }, // numeric vs string constants
+        { "=$C3/2", "=$C3/2", true }, // absolute column references
+        { "=C$3/2", "=D$3/2", true }, // absolute row references
+        { "=$E$30/2", "=$E$30/2", true }, // absolute references
+        { "=X20", "=$X$20", false }, // absolute vs relative
+        { "=X20", "=X$20", false }, // absolute vs relative
+        { "=X20", "=$X20", false }, // absolute vs relative
+        { "=X$20", "=$X20", false }, // column absolute vs row absolute
+    };
+
+    for (size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i)
+    {
+        m_pDoc->SetString(aPos1, OUString::createFromAscii(aTests[i].pFormula1));
+        m_pDoc->SetString(aPos2, OUString::createFromAscii(aTests[i].pFormula2));
+        size_t nHashVal1 = m_pDoc->GetFormulaHash(aPos1);
+        size_t nHashVal2 = m_pDoc->GetFormulaHash(aPos2);
+
+        std::ostringstream os;
+        os << "(expr1:" << aTests[i].pFormula1 << "; expr2:" << aTests[i].pFormula2 << ")";
+        if (aTests[i].bEqual)
+        {
+            os << " Error: these hashes should be equal." << endl;
+            CPPUNIT_ASSERT_MESSAGE(os.str().c_str(), nHashVal1 == nHashVal2);
+        }
+        else
+        {
+            os << " Error: these hashes should differ." << endl;
+            CPPUNIT_ASSERT_MESSAGE(os.str().c_str(), nHashVal1 != nHashVal2);
+        }
+
+        aPos1.IncRow();
+        aPos2.IncRow();
+    }
 
     m_pDoc->DeleteTab(0);
 }
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index b400f6d..a19f2e3 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -1274,6 +1274,26 @@ bool ScTokenArray::ImplGetReference( ScRange& rRange, bool bValidOnly ) const
     return bIs;
 }
 
+namespace {
+
+size_t HashSingleRef( const ScSingleRefData& rRef )
+{
+    SCsCOL nCol = rRef.Flags.bColRel ? rRef.nRelCol : rRef.nCol;
+    SCsROW nRow = rRef.Flags.bRowRel ? rRef.nRelRow : rRef.nRow;
+    SCsTAB nTab = rRef.Flags.bTabRel ? rRef.nRelTab : rRef.nTab;
+    size_t nVal = nCol;
+    nVal += (nRow << 8);
+    nVal += (nTab << 16);
+
+    // Embed flag values too.
+    nVal += rRef.Flags.bColRel;
+    nVal += (rRef.Flags.bRowRel << 1);
+    nVal += (rRef.Flags.bTabRel << 2);
+    return nVal;
+}
+
+}
+
 size_t ScTokenArray::GetHash() const
 {
     static OUStringHash aHasher;
@@ -1281,11 +1301,11 @@ size_t ScTokenArray::GetHash() const
     size_t nHash = 1;
     OpCode eOp;
     StackVar eType;
-    const FormulaToken* p;
+    const ScToken* p;
     sal_uInt16 n = std::min<sal_uInt16>(nLen, 20);
     for (sal_uInt16 i = 0; i < n; ++i)
     {
-        p = pCode[i];
+        p = static_cast<const ScToken*>(pCode[i]);
         eOp = p->GetOpCode();
         if (eOp == ocPush)
         {
@@ -1314,8 +1334,22 @@ size_t ScTokenArray::GetHash() const
                     nHash += (aHasher(rStr) << i);
                     continue;
                 }
+                case svSingleRef:
+                {

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list